Używanie interfejsu API programu Graph z platformą ASP.NET Core Blazor WebAssembly

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule wyjaśniono, jak używać interfejsu API programu Microsoft Graph w Blazor WebAssembly aplikacjach, czyli ful internetowego interfejsu API, który RESTumożliwia aplikacjom uzyskiwanie dostępu do zasobów usługi w chmurze firmy Microsoft.

Dostępne są dwie metody bezpośredniej interakcji z programem Microsoft Graph w Blazor aplikacjach:

  • Zestaw SDK programu Graph: zestawy SDK programu Microsoft Graph zostały zaprojektowane w celu uproszczenia tworzenia wysokiej jakości, wydajnych i odpornych aplikacji, które uzyskują dostęp do programu Microsoft Graph. Wybierz przycisk Zestaw SDK programu Graph w górnej części tego artykułu, aby zastosować to podejście.

  • Nazwany HttpClient z interfejsem API programu Graph: nazwany HttpClient może wysyłać żądania internetowego interfejsu API bezpośrednio do interfejsu API programu Graph. Wybierz przycisk Nazwany klient HttpClient z interfejsem API programu Graph w górnej części tego artykułu, aby zastosować to podejście.

Wskazówki zawarte w tym artykule nie dotyczą zastępowania podstawowej dokumentacji programu Microsoft Graph i dodatkowych wskazówek dotyczących zabezpieczeń platformy Azure w innych zestawach dokumentacji firmy Microsoft. Przed wdrożeniem programu Microsoft Graph w środowisku produkcyjnym należy ocenić wskazówki dotyczące zabezpieczeń w sekcji Dodatkowe zasoby tego artykułu. Postępuj zgodnie ze wszystkimi najlepszymi rozwiązaniami firmy Microsoft, aby ograniczyć obszar powierzchni ataków aplikacji.

Ważne

Scenariusze opisane w tym artykule dotyczą korzystania z usługi Microsoft Entra (ME-ID) jako dostawcy tożsamości, a nie usługi AAD B2C. Korzystanie z programu Microsoft Graph z aplikacją po stronie Blazor WebAssembly klienta i dostawcą tożsamości usługi AAD B2C nie jest obecnie obsługiwane, ponieważ aplikacja wymaga wpisu tajnego klienta, którego nie można zabezpieczyć w aplikacji po stronie Blazor klienta. W przypadku autonomicznej aplikacji usługi AAD B2C Blazor WebAssembly użyj interfejsu API programu Graph, utwórz interfejs API serwera zaplecza (internet), aby uzyskać dostęp do interfejsu API programu Graph w imieniu użytkowników. Aplikacja po stronie klienta uwierzytelnia i autoryzuje użytkowników do wywoływania internetowego interfejsu API w celu bezpiecznego uzyskiwania dostępu do programu Microsoft Graph i zwracania danych do aplikacji po stronie Blazor klienta. Wpis tajny klienta jest bezpiecznie przechowywany w internetowym interfejsie API opartym na serwerze, a nie w Blazor aplikacji na kliencie. Nigdy nie przechowuj wpisu tajnego klienta w aplikacji po stronie Blazor klienta.

Korzystanie z hostowanej Blazor WebAssembly aplikacji jest obsługiwane, gdzie Server aplikacja używa zestawu Graph SDK/interfejsu API do udostępniania danych programu Graph aplikacji za pośrednictwem internetowego interfejsu Client API. Aby uzyskać więcej informacji, zobacz sekcję Hostowane Blazor WebAssembly rozwiązania w tym artykule.

Przykłady w tym artykule korzystają z nowych funkcji platformy .NET/C#. W przypadku używania przykładów z platformą .NET 7 lub starszym wymagane są drobne modyfikacje. Jednak przykłady tekstu i kodu dotyczące interakcji z programem Microsoft Graph są takie same dla wszystkich wersji ASP.NET Core.

Poniższe wskazówki dotyczą programu Microsoft Graph w wersji 5.

Zestaw Microsoft Graph SDK do użycia w Blazor aplikacjach jest nazywany biblioteką klienta programu Microsoft Graph .NET.

Przykłady zestawu Graph SDK wymagają następujących odwołań do pakietu w aplikacji autonomicznej Blazor WebAssembly . Pierwsze dwa pakiety już odwołuje się, jeśli aplikacja została włączona na potrzeby uwierzytelniania biblioteki MSAL, na przykład podczas tworzenia aplikacji, postępując zgodnie ze wskazówkami w artykule Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Microsoft Entra.

Przykłady zestawu Graph SDK wymagają następujących odwołań do pakietu w aplikacji autonomicznej Blazor WebAssembly lub Client aplikacji hostowanego Blazor WebAssembly rozwiązania. Pierwsze dwa pakiety już odwołuje się, jeśli aplikacja została włączona na potrzeby uwierzytelniania biblioteki MSAL, na przykład podczas tworzenia aplikacji, postępując zgodnie ze wskazówkami w artykule Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Microsoft Entra.

Uwaga

Aby uzyskać instrukcje dodawania pakietów do aplikacji .NET, zobacz artykuły w sekcji Instalowanie pakietów i zarządzanie nimi w temacie Przepływ pracy użycia pakietów (dokumentacja programu NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

W witrynie Azure Portal przyznaj delegowane uprawnienia (zakresy)† dla danych programu Microsoft Graph, do których aplikacja powinna mieć dostęp w imieniu użytkownika. Na przykład w tym artykule rejestracja aplikacji powinna zawierać delegowane uprawnienia do odczytu danych użytkownika (Microsoft.Graph>User.Read zakres w uprawnieniach interfejsu API, Typ: Delegowane). Zakres User.Read umożliwia użytkownikom logowanie się do aplikacji i umożliwia aplikacji odczytywanie profilu i informacji firmowych zalogowanych użytkowników. Aby uzyskać więcej informacji, zobacz Omówienie uprawnień i zgody w Platforma tożsamości Microsoft i Omówienie uprawnień programu Microsoft Graph.

Uwaga

†Permissions i zakresy oznaczają to samo i są używane zamiennie w dokumentacji zabezpieczeń i witrynie Azure Portal. W tym artykule używane są zakresy zakresu/podczas odwoływania się do uprawnień interfejsu API programu Graph.

Po dodaniu zakresów interfejsu API programu Microsoft Graph do rejestracji aplikacji w witrynie Azure Portal dodaj następującą konfigurację ustawień aplikacji do wwwroot/appsettings.json pliku w aplikacji, który zawiera podstawowy adres URL programu Graph z wersją i zakresami programu Microsoft Graph. W poniższym przykładzie User.Read zakres jest określony dla przykładów w kolejnych sekcjach tego artykułu. Zakresy nie są uwzględniane wielkości liter.

"MicrosoftGraph": {
  "BaseUrl": "https://graph.microsoft.com/{VERSION}/",
  "Scopes": [
    "user.read"
  ]
}

W poprzednim przykładzie {VERSION} symbol zastępczy jest wersją interfejsu API programu Microsoft Graph (na przykład: v1.0). Końcowy ukośnik jest wymagany.

Poniżej przedstawiono przykład kompletnego wwwroot/appsettings.json pliku konfiguracji dla aplikacji, która używa identyfikatora ME-ID jako dostawcy tożsamości, gdzie odczytywanie danych użytkownika (user.read zakres) jest określone dla programu Microsoft Graph:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT ID}",
    "ValidateAuthority": true
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0/",
    "Scopes": [
      "user.read"
    ]
  }
}

W poprzednim przykładzie {TENANT ID} symbol zastępczy to identyfikator katalogu (dzierżawy), a {CLIENT ID} symbol zastępczy to identyfikator aplikacji (klienta). Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Dodaj następującą GraphClientExtensions klasę do aplikacji autonomicznej. Zakresy są dostarczane do Scopes właściwości AccessTokenRequestOptions w metodzie AuthenticateRequestAsync .

Dodaj następującą GraphClientExtensions klasę do autonomicznej aplikacji lub Client aplikacji hostowanego Blazor WebAssemblyrozwiązania. Zakresy są dostarczane do Scopes właściwości AccessTokenRequestOptions w metodzie AuthenticateRequestAsync .

Jeśli token dostępu nie zostanie uzyskany, poniższy kod nie ustawia nagłówka autoryzacji elementu nośnego dla żądań programu Graph.

GraphClientExtensions.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Authentication.WebAssembly.Msal.Models;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Authentication;
using IAccessTokenProvider = 
    Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider;

namespace BlazorSample;

internal static class GraphClientExtensions
{
    public static IServiceCollection AddGraphClient(
            this IServiceCollection services, string? baseUrl, List<string>? scopes)
    {
        if (string.IsNullOrEmpty(baseUrl) || scopes?.Count == 0)
        {
            return services;
        }

        services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
            options =>
            {
                scopes?.ForEach((scope) =>
                {
                    options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
                });
            });

        services.AddScoped<IAuthenticationProvider, GraphAuthenticationProvider>();

        services.AddScoped(sp =>
        {
            return new GraphServiceClient(
                new HttpClient(),
                sp.GetRequiredService<IAuthenticationProvider>(),
                baseUrl);
        });

        return services;
    }

    private class GraphAuthenticationProvider(IAccessTokenProvider tokenProvider, 
        IConfiguration config) : IAuthenticationProvider
    {
        private readonly IConfiguration config = config;

        public IAccessTokenProvider TokenProvider { get; } = tokenProvider;

        public async Task AuthenticateRequestAsync(RequestInformation request, 
            Dictionary<string, object>? additionalAuthenticationContext = null, 
            CancellationToken cancellationToken = default)
        {
            var result = await TokenProvider.RequestAccessToken(
                new AccessTokenRequestOptions()
                {
                    Scopes = 
                        config.GetSection("MicrosoftGraph:Scopes").Get<string[]>()
                });

            if (result.TryGetToken(out var token))
            {
                request.Headers.Add("Authorization", 
                    $"{CoreConstants.Headers.Bearer} {token.Value}");
            }
        }
    }
}

Ważne

Zobacz sekcję versusAdditionalScopesToConsent, aby zapoznać się z DefaultAccessTokenScopes wyjaśnieniem, dlaczego powyższy kod używa DefaultAccessTokenScopes metody do dodawania zakresów, a nie AdditionalScopesToConsent.

Program W pliku dodaj usługi klienta programu Graph i konfigurację przy użyciu AddGraphClient metody rozszerzenia:

var baseUrl = builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"];
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>();

builder.Services.AddGraphClient(baseUrl, scopes);

Wywoływanie interfejsu API programu Graph ze składnika przy użyciu zestawu Graph SDK

UserData Poniższy składnik używa wstrzykniętego GraphServiceClient elementu, aby uzyskać dane profilu ME-ID użytkownika i wyświetlić jego numer telefonu komórkowego.

W przypadku dowolnego użytkownika testowego utworzonego w obszarze ME-ID upewnij się, że w witrynie Azure Portal nadasz profilowi ME-ID użytkownika numer telefonu komórkowego.

UserData.razor:

@page "/user-data"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Graph
@attribute [Authorize]
@inject GraphServiceClient Client

<PageTitle>User Data</PageTitle>

<h1>Microsoft Graph User Data</h1>

@if (!string.IsNullOrEmpty(user?.MobilePhone))
{
    <p>Mobile Phone: @user.MobilePhone</p>
}

@code {
    private Microsoft.Graph.Models.User? user;

    protected override async Task OnInitializedAsync()
    {
        user = await Client.Me.GetAsync();
    }
}

Dodaj link do strony składnika w składniku NavMenu (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-data">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Data
    </NavLink>
</div>

Podczas testowania za pomocą zestawu Graph SDK lokalnie zalecamy użycie nowej sesji przeglądarki InPrivate/incognito dla każdego testu, aby zapobiec cookiezakłócaniu testów. Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Dostosowywanie oświadczeń użytkowników przy użyciu zestawu Graph SDK

W poniższym przykładzie aplikacja tworzy oświadczenia dotyczące numeru telefonu komórkowego i lokalizacji biura dla użytkownika na podstawie danych profilu użytkownika ME-ID. Aplikacja musi mieć zakres interfejsu User.Read API programu Graph skonfigurowany w polu ME-ID. Wszyscy użytkownicy testowi w tym scenariuszu muszą mieć numer telefonu komórkowego i lokalizację biura w profilu ME-ID, który można dodać za pośrednictwem witryny Azure Portal.

W następującej niestandardowej fabryce kont użytkowników:

  • Element ILogger (logger) jest dołączany dla wygody w przypadku, gdy chcesz rejestrować informacje lub błędy w metodzie CreateUserAsync .
  • W przypadku zgłoszenia AccessTokenNotAvailableException użytkownik jest przekierowywany do dostawcy tożsamości w celu zalogowania się na swoje konto. Dodatkowe lub różne akcje można wykonać w przypadku niepowodzenia żądania tokenu dostępu. Na przykład aplikacja może zarejestrować AccessTokenNotAvailableException i utworzyć bilet pomocy technicznej w celu dalszego zbadania.
  • RemoteUserAccount Platforma reprezentuje konto użytkownika. Jeśli aplikacja wymaga niestandardowej klasy konta użytkownika, która rozszerza RemoteUserAccountklasę , zamień niestandardową klasę konta użytkownika na RemoteUserAccount wartość w poniższym kodzie.

CustomAccountFactory.cs:

using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions.Authentication;

namespace BlazorSample;

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider, ILogger<CustomAccountFactory> logger,
        IConfiguration config) 
    : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;
    private readonly string? baseUrl = 
        config.GetSection("MicrosoftGraph")["BaseUrl"];

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null &&
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null && !string.IsNullOrEmpty(baseUrl))
            {
                try
                {
                    var client = new GraphServiceClient(
                        new HttpClient(),
                        serviceProvider
                            .GetRequiredService<IAuthenticationProvider>(),
                        baseUrl);

                    var user = await client.Me.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Skonfiguruj uwierzytelnianie MSAL tak, aby używało niestandardowej fabryki kont użytkowników.

Upewnij się, że Program plik używa Microsoft.AspNetCore.Components.WebAssembly.Authentication przestrzeni nazw:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Przykład w tej sekcji opiera się na podejściu odczytu podstawowego adresu URL z wersjami i zakresami z konfiguracji aplikacji za pośrednictwem MicrosoftGraph sekcji w wwwroot/appsettings.json pliku. Następujące wiersze powinny już znajdować się w Program pliku, postępując zgodnie ze wskazówkami zawartymi wcześniej w tym artykule:

var baseUrl = builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"];
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>();

builder.Services.AddGraphClient(baseUrl, scopes);

Program W pliku znajdź wywołanie AddMsalAuthentication metody rozszerzenia. Zaktualizuj kod do poniższej, która zawiera wywołanie, które AddAccountClaimsPrincipalFactory dodaje fabrykę oświadczeń konta z fabryką CustomAccountFactory.

Jeśli aplikacja używa niestandardowej klasy konta użytkownika, która rozszerza RemoteUserAccountklasę , zamień niestandardową klasę konta użytkownika na RemoteUserAccount w poniższym kodzie.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    RemoteUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", 
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
        CustomAccountFactory>();

Możesz użyć następującego UserClaims składnika do zbadania oświadczeń użytkownika po uwierzytelnieniu użytkownika za pomocą me-ID:

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}
else
{
    <p>No claims found.</p>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        claims = user.Claims;
    }
}

Dodaj link do strony składnika w składniku NavMenu (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-claims">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Claims
    </NavLink>
</div>

Podczas testowania za pomocą zestawu Graph SDK lokalnie zalecamy użycie nowej sesji przeglądarki InPrivate/incognito dla każdego testu, aby zapobiec cookiezakłócaniu testów. Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Poniższe wskazówki dotyczą programu Microsoft Graph w wersji 4. Jeśli uaktualniasz aplikację z zestawu SDK w wersji 4 do wersji 5, zobacz Dziennik zmian i uaktualnianie zestawu SDK platformy .NET programu Microsoft Graph w wersji 5.

Zestaw Microsoft Graph SDK do użycia w Blazor aplikacjach jest nazywany biblioteką klienta programu Microsoft Graph .NET.

Przykłady zestawu Graph SDK wymagają następujących odwołań do pakietu w aplikacji autonomicznej Blazor WebAssembly . Pierwsze dwa pakiety już odwołuje się, jeśli aplikacja została włączona na potrzeby uwierzytelniania biblioteki MSAL, na przykład podczas tworzenia aplikacji, postępując zgodnie ze wskazówkami w artykule Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Microsoft Entra.

Przykłady zestawu Graph SDK wymagają następujących odwołań do pakietu w aplikacji autonomicznej Blazor WebAssembly lub Client aplikacji hostowanego Blazor WebAssembly rozwiązania. Pierwsze dwa pakiety już odwołuje się, jeśli aplikacja została włączona na potrzeby uwierzytelniania biblioteki MSAL, na przykład podczas tworzenia aplikacji, postępując zgodnie ze wskazówkami w artykule Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Microsoft Entra.

Uwaga

Aby uzyskać instrukcje dodawania pakietów do aplikacji .NET, zobacz artykuły w sekcji Instalowanie pakietów i zarządzanie nimi w temacie Przepływ pracy użycia pakietów (dokumentacja programu NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

W witrynie Azure Portal przyznaj delegowane uprawnienia (zakresy)† dla danych programu Microsoft Graph, do których aplikacja powinna mieć dostęp w imieniu użytkownika. Na przykład w tym artykule rejestracja aplikacji powinna zawierać delegowane uprawnienia do odczytu danych użytkownika (Microsoft.Graph>User.Read zakres w uprawnieniach interfejsu API, Typ: Delegowane). Zakres User.Read umożliwia użytkownikom logowanie się do aplikacji i umożliwia aplikacji odczytywanie profilu i informacji firmowych zalogowanych użytkowników. Aby uzyskać więcej informacji, zobacz Omówienie uprawnień i zgody w Platforma tożsamości Microsoft i Omówienie uprawnień programu Microsoft Graph.

Uwaga

†Permissions i zakresy oznaczają to samo i są używane zamiennie w dokumentacji zabezpieczeń i witrynie Azure Portal. W tym artykule używane są zakresy zakresu/podczas odwoływania się do uprawnień interfejsu API programu Graph.

Po dodaniu zakresów interfejsu API programu Microsoft Graph do rejestracji aplikacji w witrynie Azure Portal dodaj następującą konfigurację ustawień aplikacji do wwwroot/appsettings.json pliku w aplikacji, który zawiera podstawowy adres URL programu Graph z wersją i zakresami programu Microsoft Graph. W poniższym przykładzie User.Read zakres jest określony dla przykładów w kolejnych sekcjach tego artykułu. Zakresy nie są uwzględniane wielkości liter.

"MicrosoftGraph": {
  "BaseUrl": "https://graph.microsoft.com/{VERSION}/",
  "Scopes": [
    "user.read"
  ]
}

W poprzednim przykładzie {VERSION} symbol zastępczy jest wersją interfejsu API programu Microsoft Graph (na przykład: v1.0). Końcowy ukośnik jest wymagany.

Poniżej przedstawiono przykład kompletnego wwwroot/appsettings.json pliku konfiguracji dla aplikacji, która używa identyfikatora ME-ID jako dostawcy tożsamości, gdzie odczytywanie danych użytkownika (user.read zakres) jest określone dla programu Microsoft Graph:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT ID}",
    "ValidateAuthority": true
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0/",
    "Scopes": [
      "user.read"
    ]
  }
}

W poprzednim przykładzie {TENANT ID} symbol zastępczy to identyfikator katalogu (dzierżawy), a {CLIENT ID} symbol zastępczy to identyfikator aplikacji (klienta). Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Dodaj następującą GraphClientExtensions klasę do aplikacji autonomicznej. Zakresy są dostarczane do Scopes właściwości AccessTokenRequestOptions w metodzie AuthenticateRequestAsync . Parametr IHttpProvider.OverallTimeout jest rozszerzony z wartości domyślnej 100 sekund do 300 sekund, aby dać HttpClient więcej czasu na odebranie odpowiedzi z programu Microsoft Graph.

Dodaj następującą GraphClientExtensions klasę do autonomicznej aplikacji lub Client aplikacji hostowanego Blazor WebAssemblyrozwiązania. Zakresy są dostarczane do Scopes właściwości AccessTokenRequestOptions w metodzie AuthenticateRequestAsync . Parametr IHttpProvider.OverallTimeout jest rozszerzony z wartości domyślnej 100 sekund do 300 sekund, aby dać HttpClient więcej czasu na odebranie odpowiedzi z programu Microsoft Graph.

Jeśli token dostępu nie zostanie uzyskany, poniższy kod nie ustawia nagłówka autoryzacji elementu nośnego dla żądań programu Graph.

GraphClientExtensions.cs:

using System.Net.Http.Headers;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.Authentication.WebAssembly.Msal.Models;
using Microsoft.Graph;

namespace BlazorSample;

internal static class GraphClientExtensions
{
    public static IServiceCollection AddGraphClient(
        this IServiceCollection services, string? baseUrl, List<string>? scopes)
    {
        if (string.IsNullOrEmpty(baseUrl) || scopes?.Count == 0)
        {
            return services;
        }

        services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
            options =>
            {
                scopes?.ForEach((scope) =>
                {
                    options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
                });
            });

        services.AddScoped<IAuthenticationProvider, GraphAuthenticationProvider>();

        services.AddScoped<IHttpProvider, HttpClientHttpProvider>(sp =>
            new HttpClientHttpProvider(new HttpClient()));

        services.AddScoped(sp =>
        {
            return new GraphServiceClient(
                baseUrl,
                sp.GetRequiredService<IAuthenticationProvider>(),
                sp.GetRequiredService<IHttpProvider>());
        });

        return services;
    }

    private class GraphAuthenticationProvider(IAccessTokenProvider tokenProvider, 
        IConfiguration config) : IAuthenticationProvider
    {
        private readonly IConfiguration config = config;

        public IAccessTokenProvider TokenProvider { get; } = tokenProvider;

        public async Task AuthenticateRequestAsync(HttpRequestMessage request)
        {
            var result = await TokenProvider.RequestAccessToken(
                new AccessTokenRequestOptions()
                { 
                    Scopes = config.GetSection("MicrosoftGraph:Scopes").Get<string[]>()
                });

            if (result.TryGetToken(out var token))
            {
                request.Headers.Authorization ??= new AuthenticationHeaderValue(
                    "Bearer", token.Value);
            }
        }
    }

    private class HttpClientHttpProvider(HttpClient client) : IHttpProvider
    {
        private readonly HttpClient client = client;

        public ISerializer Serializer { get; } = new Serializer();

        public TimeSpan OverallTimeout { get; set; } = TimeSpan.FromSeconds(300);

        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
        {
            return client.SendAsync(request);
        }

        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            HttpCompletionOption completionOption,
            CancellationToken cancellationToken)
        {
            return client.SendAsync(request, completionOption, cancellationToken);
        }

        public void Dispose()
        {
        }
    }
}

Ważne

Zobacz sekcję versusAdditionalScopesToConsent, aby zapoznać się z DefaultAccessTokenScopes wyjaśnieniem, dlaczego powyższy kod używa DefaultAccessTokenScopes metody do dodawania zakresów, a nie AdditionalScopesToConsent.

Program W pliku dodaj usługi klienta programu Graph i konfigurację przy użyciu AddGraphClient metody rozszerzenia:

var baseUrl = builder.Configuration
    .GetSection("MicrosoftGraph")["BaseUrl"];
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>();

builder.Services.AddGraphClient(baseUrl, scopes);

Wywoływanie interfejsu API programu Graph ze składnika przy użyciu zestawu Graph SDK

UserData Poniższy składnik używa wstrzykniętego GraphServiceClient elementu, aby uzyskać dane profilu ME-ID użytkownika i wyświetlić jego numer telefonu komórkowego. W przypadku dowolnego użytkownika testowego utworzonego w obszarze ME-ID upewnij się, że w witrynie Azure Portal nadasz profilowi ME-ID użytkownika numer telefonu komórkowego.

UserData.razor:

@page "/user-data"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.Graph
@attribute [Authorize]
@inject GraphServiceClient Client

<PageTitle>User Data</PageTitle>

<h1>Microsoft Graph User Data</h1>

@if (!string.IsNullOrEmpty(user?.MobilePhone))
{
    <p>Mobile Phone: @user.MobilePhone</p>
}

@code {
    private Microsoft.Graph.User? user;

    protected override async Task OnInitializedAsync()
    {
        var request = Client.Me.Request();
        user = await request.GetAsync();
    }
}

Dodaj link do strony składnika w składniku NavMenu (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-data">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Data
    </NavLink>
</div>

Podczas testowania za pomocą zestawu Graph SDK lokalnie zalecamy użycie nowej sesji przeglądarki InPrivate/incognito dla każdego testu, aby zapobiec cookiezakłócaniu testów. Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Dostosowywanie oświadczeń użytkowników przy użyciu zestawu Graph SDK

W poniższym przykładzie aplikacja tworzy oświadczenia dotyczące numeru telefonu komórkowego i lokalizacji biura dla użytkownika na podstawie danych profilu użytkownika ME-ID. Aplikacja musi mieć zakres interfejsu User.Read API programu Graph skonfigurowany w polu ME-ID. Wszyscy użytkownicy testowi w tym scenariuszu muszą mieć numer telefonu komórkowego i lokalizację biura w profilu ME-ID, który można dodać za pośrednictwem witryny Azure Portal.

W następującej niestandardowej fabryce kont użytkowników:

  • Element ILogger (logger) jest dołączany dla wygody w przypadku, gdy chcesz rejestrować informacje lub błędy w metodzie CreateUserAsync .
  • W przypadku zgłoszenia AccessTokenNotAvailableException użytkownik jest przekierowywany do dostawcy tożsamości w celu zalogowania się na swoje konto. Dodatkowe lub różne akcje można wykonać w przypadku niepowodzenia żądania tokenu dostępu. Na przykład aplikacja może zarejestrować AccessTokenNotAvailableException i utworzyć bilet pomocy technicznej w celu dalszego zbadania.
  • RemoteUserAccount Platforma reprezentuje konto użytkownika. Jeśli aplikacja wymaga niestandardowej klasy konta użytkownika, która rozszerza RemoteUserAccountklasę , zamień niestandardową klasę konta użytkownika na RemoteUserAccount wartość w poniższym kodzie.

CustomAccountFactory.cs:

using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;

namespace BlazorSample;

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor, 
        IServiceProvider serviceProvider, ILogger<CustomAccountFactory> logger)
    : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null && 
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null)
            {
                try
                {
                    var client = ActivatorUtilities
                        .CreateInstance<GraphServiceClient>(serviceProvider);
                    var request = client.Me.Request();
                    var user = await request.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Skonfiguruj uwierzytelnianie MSAL tak, aby używało niestandardowej fabryki kont użytkowników.

Upewnij się, że Program plik używa Microsoft.AspNetCore.Components.WebAssembly.Authentication przestrzeni nazw:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Przykład w tej sekcji opiera się na podejściu odczytu podstawowego adresu URL z wersjami i zakresami z konfiguracji aplikacji za pośrednictwem MicrosoftGraph sekcji w wwwroot/appsettings.json pliku. Następujące wiersze powinny już znajdować się w Program pliku, postępując zgodnie ze wskazówkami zawartymi wcześniej w tym artykule:

var baseUrl = string.Join("/", 
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"];
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>();

builder.Services.AddGraphClient(baseUrl, scopes);

Program W pliku znajdź wywołanie AddMsalAuthentication metody rozszerzenia. Zaktualizuj kod do poniższej, która zawiera wywołanie, które AddAccountClaimsPrincipalFactory dodaje fabrykę oświadczeń konta z fabryką CustomAccountFactory.

Jeśli aplikacja używa niestandardowej klasy konta użytkownika, która rozszerza RemoteUserAccountklasę , zamień niestandardową klasę konta użytkownika na RemoteUserAccount w poniższym kodzie.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    RemoteUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", 
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
        CustomAccountFactory>();

Możesz użyć następującego UserClaims składnika do zbadania oświadczeń użytkownika po uwierzytelnieniu użytkownika za pomocą me-ID:

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}
else
{
    <p>No claims found.</p>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        claims = user.Claims;
    }
}

Dodaj link do strony składnika w składniku NavMenu (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-claims">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Claims
    </NavLink>
</div>

Podczas testowania za pomocą zestawu Graph SDK lokalnie zalecamy użycie nowej sesji przeglądarki InPrivate/incognito dla każdego testu, aby zapobiec cookiezakłócaniu testów. Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

W poniższych przykładach użyto wywołań interfejsu API programu Graph o nazwie HttpClient w celu uzyskania numeru telefonu komórkowego użytkownika w celu przetworzenia połączenia lub dostosowania oświadczeń użytkownika w celu uwzględnienia oświadczenia numeru telefonu komórkowego i oświadczenia lokalizacji biura.

Przykłady wymagają odwołania do pakietu dla Microsoft.Extensions.Http aplikacji autonomicznej Blazor WebAssembly .

Przykłady wymagają odwołania do pakietu dla Microsoft.Extensions.Http aplikacji autonomicznej Blazor WebAssembly lub Client aplikacji hostowanego Blazor WebAssembly rozwiązania.

Uwaga

Aby uzyskać instrukcje dodawania pakietów do aplikacji .NET, zobacz artykuły w sekcji Instalowanie pakietów i zarządzanie nimi w temacie Przepływ pracy użycia pakietów (dokumentacja programu NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

W witrynie Azure Portal przyznaj delegowane uprawnienia (zakresy)† dla danych programu Microsoft Graph, do których aplikacja powinna mieć dostęp w imieniu użytkownika. Na przykład w tym artykule rejestracja aplikacji powinna zawierać delegowane uprawnienia do odczytu danych użytkownika (Microsoft.Graph>User.Read zakres w uprawnieniach interfejsu API, Typ: Delegowane). Zakres User.Read umożliwia użytkownikom logowanie się do aplikacji i umożliwia aplikacji odczytywanie profilu i informacji firmowych zalogowanych użytkowników. Aby uzyskać więcej informacji, zobacz Omówienie uprawnień i zgody w Platforma tożsamości Microsoft i Omówienie uprawnień programu Microsoft Graph.

Uwaga

†Permissions i zakresy oznaczają to samo i są używane zamiennie w dokumentacji zabezpieczeń i witrynie Azure Portal. W tym artykule używane są zakresy zakresu/podczas odwoływania się do uprawnień interfejsu API programu Graph.

Po dodaniu zakresów interfejsu API programu Microsoft Graph do rejestracji aplikacji w witrynie Azure Portal dodaj następującą konfigurację ustawień aplikacji do wwwroot/appsettings.json pliku w aplikacji, który zawiera podstawowy adres URL programu Graph z wersją i zakresami programu Microsoft Graph. W poniższym przykładzie User.Read zakres jest określony dla przykładów w kolejnych sekcjach tego artykułu. Zakresy nie są uwzględniane wielkości liter.

"MicrosoftGraph": {
  "BaseUrl": "https://graph.microsoft.com/{VERSION}/",
  "Scopes": [
    "user.read"
  ]
}

W poprzednim przykładzie {VERSION} symbol zastępczy jest wersją interfejsu API programu Microsoft Graph (na przykład: v1.0). Końcowy ukośnik jest wymagany.

Poniżej przedstawiono przykład kompletnego wwwroot/appsettings.json pliku konfiguracji dla aplikacji, która używa identyfikatora ME-ID jako dostawcy tożsamości, gdzie odczytywanie danych użytkownika (user.read zakres) jest określone dla programu Microsoft Graph:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT ID}",
    "ValidateAuthority": true
  },
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/v1.0/",
    "Scopes": [
      "user.read"
    ]
  }
}

W poprzednim przykładzie {TENANT ID} symbol zastępczy to identyfikator katalogu (dzierżawy), a {CLIENT ID} symbol zastępczy to identyfikator aplikacji (klienta). Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Utwórz następującą GraphAuthorizationMessageHandler klasę i konfigurację Program projektu w pliku na potrzeby pracy z interfejsem API programu Graph. Podstawowy adres URL i zakresy są dostarczane do programu obsługi z konfiguracji.

GraphAuthorizationMessageHandler.cs:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

namespace BlazorSample;

public class GraphAuthorizationMessageHandler : AuthorizationMessageHandler
{
    public GraphAuthorizationMessageHandler(IAccessTokenProvider provider,
        NavigationManager navigation, IConfiguration config)
        : base(provider, navigation)
    {
        ConfigureHandler(
            authorizedUrls: [ config.GetSection("MicrosoftGraph")["BaseUrl"] ?? 
                string.Empty ],
            scopes: config.GetSection("MicrosoftGraph:Scopes").Get<List<string>>());
    }
}

Program W pliku skonfiguruj nazwę interfejsu HttpClient API programu Graph:

builder.Services.AddTransient<GraphAuthorizationMessageHandler>();

builder.Services.AddHttpClient("GraphAPI",
        client => client.BaseAddress = new Uri(
            builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ?? 
                string.Empty))
    .AddHttpMessageHandler<GraphAuthorizationMessageHandler>();

W poprzednim przykładzie parametr GraphAuthorizationMessageHandlerDelegatingHandler jest zarejestrowany jako usługa przejściowa dla elementu AddHttpMessageHandler. Rejestracja przejściowa jest zalecana w przypadku IHttpClientFactoryprogramu , który zarządza własnymi zakresami di. Aby uzyskać więcej informacji, zobacz następujące zasoby:

Wywoływanie interfejsu API programu Graph ze składnika przy użyciu nazwanego elementu HttpClient

Klasa UserInfo.cs wyznacza wymagane właściwości profilu użytkownika z atrybutem JsonPropertyNameAttribute i JSnazwą ON używaną przez me-ID. Poniższy przykład konfiguruje właściwości numeru telefonu komórkowego i lokalizacji biura użytkownika.

UserInfo.cs:

using System.Text.Json.Serialization;

namespace BlazorSample;

public class UserInfo
{
    [JsonPropertyName("mobilePhone")]
    public string? MobilePhone { get; set; }

    [JsonPropertyName("officeLocation")]
    public string? OfficeLocation { get; set; }
}

W poniższym UserData składniku tworzony jest interfejs API programu Graph w HttpClient celu wystawienia żądania dotyczącego danych profilu użytkownika. Zasób me (me) jest dodawany do podstawowego adresu URL z wersją żądania interfejsu API programu Graph. JSDane zwracane przez program Graph są deserializowane we właściwościach UserInfo klasy. W poniższym przykładzie otrzymany jest numer telefonu komórkowego. Możesz dodać podobny kod, aby uwzględnić lokalizację biura profilu ME-ID użytkownika, jeśli chcesz (userInfo.OfficeLocation). Jeśli żądanie tokenu dostępu zakończy się niepowodzeniem, użytkownik zostanie przekierowany w celu zalogowania się do aplikacji w celu uzyskania nowego tokenu dostępu.

UserData.razor:

@page "/user-data"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@attribute [Authorize]
@inject IConfiguration Config
@inject IHttpClientFactory ClientFactory

<PageTitle>User Data</PageTitle>

<h1>Microsoft Graph User Data</h1>

@if (!string.IsNullOrEmpty(userInfo?.MobilePhone))
{
    <p>Mobile Phone: @userInfo.MobilePhone</p>
}

@code {
    private UserInfo? userInfo;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            var client = ClientFactory.CreateClient("GraphAPI");

            userInfo = await client.GetFromJsonAsync<UserInfo>("me");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

Dodaj link do strony składnika w składniku NavMenu (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-data">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Data
    </NavLink>
</div>

W poniższej sekwencji opisano nowy przepływ użytkownika dla zakresów interfejsu API programu Graph:

  1. Nowy użytkownik loguje się do aplikacji po raz pierwszy.
  2. Użytkownik wyraża zgodę na korzystanie z aplikacji w interfejsie użytkownika zgody platformy Azure.
  3. Użytkownik uzyskuje dostęp do strony składnika, która żąda danych interfejsu API programu Graph po raz pierwszy.
  4. Użytkownik jest przekierowywany do interfejsu użytkownika zgody platformy Azure, aby wyrazić zgodę na zakresy interfejsu API programu Graph.
  5. Zwracane są dane użytkownika interfejsu API programu Graph.

Jeśli wolisz aprowizacja zakresu (zgoda dla zakresów interfejsu API programu Graph) odbywa się podczas początkowego logowania, podaj zakresy uwierzytelniania MSAL jako domyślne zakresy tokenu dostępu w Program pliku:

+ var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
+     .Get<List<string>>() ?? [];

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);

+   foreach (var scope in scopes)
+   {
+       options.ProviderOptions.DefaultAccessTokenScopes.Add(scope);
+   }
});

Ważne

Zobacz sekcję versusAdditionalScopesToConsent, aby zapoznać się z DefaultAccessTokenScopes wyjaśnieniem, dlaczego powyższy kod używa DefaultAccessTokenScopes metody do dodawania zakresów, a nie AdditionalScopesToConsent.

Po wprowadzeniu powyższych zmian w aplikacji przepływ użytkownika przyjmuje następującą sekwencję:

  1. Nowy użytkownik loguje się do aplikacji po raz pierwszy.
  2. Użytkownik wyraża zgodę na korzystanie z zakresów aplikacji i interfejsu API programu Graph w interfejsie użytkownika zgody platformy Azure.
  3. Użytkownik uzyskuje dostęp do strony składnika, która żąda danych interfejsu API programu Graph po raz pierwszy.
  4. Zwracane są dane użytkownika interfejsu API programu Graph.

Podczas testowania przy użyciu interfejsu API programu Graph lokalnie zalecamy użycie nowej sesji przeglądarki InPrivate/incognito dla każdego testu, aby zapobiec cookiezakłócaniu testowania. Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Dostosowywanie oświadczeń użytkowników przy użyciu nazwanego HttpClient

W poniższym przykładzie aplikacja tworzy oświadczenia dotyczące numeru telefonu komórkowego i lokalizacji biura dla użytkownika na podstawie danych profilu użytkownika ME-ID. Aplikacja musi mieć zakres interfejsu User.Read API programu Graph skonfigurowany w polu ME-ID. Konta użytkowników testowych w identyfikatorze ME wymagają wpisu dla numeru telefonu komórkowego i lokalizacji biura, które można dodać za pośrednictwem witryny Azure Portal do profilów użytkowników.

Jeśli klasa nie została jeszcze dodana UserInfo do aplikacji, postępując zgodnie ze wskazówkami wcześniej w tym artykule, dodaj następującą klasę i wyznaczysz wymagane właściwości profilu użytkownika za pomocą atrybutu JsonPropertyNameAttribute i JSnazwy ON używanej przez me-ID. Poniższy przykład konfiguruje właściwości numeru telefonu komórkowego i lokalizacji biura użytkownika.

UserInfo.cs:

using System.Text.Json.Serialization;

namespace BlazorSample;

public class UserInfo
{
    [JsonPropertyName("mobilePhone")]
    public string? MobilePhone { get; set; }

    [JsonPropertyName("officeLocation")]
    public string? OfficeLocation { get; set; }
}

W następującej niestandardowej fabryce kont użytkowników:

  • Element ILogger (logger) jest dołączany dla wygody w przypadku, gdy chcesz rejestrować informacje lub błędy w metodzie CreateUserAsync .
  • W przypadku zgłoszenia AccessTokenNotAvailableException użytkownik jest przekierowywany do dostawcy tożsamości w celu zalogowania się na swoje konto. Dodatkowe lub różne akcje można wykonać w przypadku niepowodzenia żądania tokenu dostępu. Na przykład aplikacja może zarejestrować AccessTokenNotAvailableException i utworzyć bilet pomocy technicznej w celu dalszego zbadania.
  • RemoteUserAccount Platforma reprezentuje konto użytkownika. Jeśli aplikacja wymaga niestandardowej klasy konta użytkownika, która rozszerza RemoteUserAccountklasę , zamień niestandardową klasę konta użytkownika na RemoteUserAccount wartość w poniższym kodzie.

CustomAccountFactory.cs:

using System.Net.Http.Json;
using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;

namespace BlazorSample;

public class CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IHttpClientFactory clientFactory,
        ILogger<CustomAccountFactory> logger)
    : AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IHttpClientFactory clientFactory = clientFactory;

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        RemoteUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null && 
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null)
            {
                try
                {
                    var client = clientFactory.CreateClient("GraphAPI");

                    var userInfo = await client.GetFromJsonAsync<UserInfo>("me");

                    if (userInfo is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            userInfo.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            userInfo.OfficeLocation ?? "Not set"));
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Uwierzytelnianie MSAL jest skonfigurowane do używania niestandardowej fabryki kont użytkowników. Zacznij od potwierdzenia, że Program plik używa Microsoft.AspNetCore.Components.WebAssembly.Authentication przestrzeni nazw:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Program W pliku znajdź wywołanie AddMsalAuthentication metody rozszerzenia. Zaktualizuj kod do poniższej, która zawiera wywołanie, które AddAccountClaimsPrincipalFactory dodaje fabrykę oświadczeń konta z fabryką CustomAccountFactory.

Jeśli aplikacja używa niestandardowej klasy konta użytkownika, która rozszerza RemoteUserAccountklasę , zamień niestandardową klasę konta użytkownika aplikacji na RemoteUserAccount wartość w poniższym kodzie.

builder.Services.AddMsalAuthentication<RemoteAuthenticationState, 
    RemoteUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd", 
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount, 
        CustomAccountFactory>();

Powyższy przykład dotyczy aplikacji korzystającej z uwierzytelniania ME-ID z biblioteką MSAL. Podobne wzorce istnieją dla uwierzytelniania OIDC i interfejsu API. Aby uzyskać więcej informacji, zobacz przykłady w sekcji Dostosowywanie użytkownika z oświadczeniem ładunku w artykule ASP.NET Core Blazor WebAssembly dodatkowe scenariusze zabezpieczeń.

Możesz użyć następującego UserClaims składnika do zbadania oświadczeń użytkownika po uwierzytelnieniu użytkownika za pomocą me-ID:

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li>@claim.Type: @claim.Value</li>
        }
    </ul>
}
else
{
    <p>No claims found.</p>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthenticationStateProvider
            .GetAuthenticationStateAsync();
        var user = authState.User;

        claims = user.Claims;
    }
}

Dodaj link do strony składnika w składniku NavMenu (Layout/NavMenu.razor):

<div class="nav-item px-3">
    <NavLink class="nav-link" href="user-claims">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> User Claims
    </NavLink>
</div>

Podczas testowania przy użyciu interfejsu API programu Graph lokalnie zalecamy użycie nowej sesji przeglądarki InPrivate/incognito dla każdego testu, aby zapobiec cookiezakłócaniu testowania. Aby uzyskać więcej informacji, zobacz Secure an ASP.NET Core standalone app with Microsoft Entra ID (Zabezpieczanie autonomicznej aplikacji ASP.NET Core Blazor WebAssembly przy użyciu identyfikatora Entra firmy Microsoft).

Przypisywanie użytkowników do rejestracji aplikacji z rolami aplikacji lub bez tych ról

Możesz dodać użytkowników do rejestracji aplikacji i przypisać role do użytkowników, wykonując następujące kroki w witrynie Azure Portal.

Aby dodać użytkownika, wybierz pozycję Użytkownicy w obszarze ME-ID w witrynie Azure Portal:

  1. Wybierz pozycję Nowy użytkownik>Utwórz nowego użytkownika.
  2. Użyj szablonu Tworzenie użytkownika .
  3. Podaj informacje użytkownika w Identity obszarze.
  4. Możesz wygenerować początkowe hasło lub przypisać początkowe hasło, które użytkownik zmieni podczas pierwszego logowania. Jeśli używasz hasła wygenerowanego przez portal, zanotuj je teraz.
  5. Wybierz pozycję Utwórz , aby utworzyć użytkownika. Po zamknięciu pozycji Utwórz nowy interfejs użytkownika wybierz pozycję Odśwież , aby zaktualizować listę użytkowników i wyświetlić nowego użytkownika.
  6. W przykładach w tym artykule przypisz numer telefonu komórkowego do nowego użytkownika, wybierając jego nazwę z listy użytkowników, wybierając pozycję Właściwości i edytując informacje kontaktowe, aby podać numer telefonu komórkowego.

Aby przypisać użytkowników do aplikacji bez ról aplikacji:

  1. W obszarze ME-ID w witrynie Azure Portal otwórz aplikacje dla przedsiębiorstw.
  2. Wybierz aplikację z listy.
  3. Wybierz pozycję Użytkownicy i grupy.
  4. Wybierz pozycję Dodaj użytkownika/grupę.
  5. Wybierz użytkownika.
  6. Wybierz przycisk Przypisz.

Aby przypisać użytkowników do aplikacji z rolami aplikacji:

  1. Dodaj role do rejestracji aplikacji w witrynie Azure Portal, postępując zgodnie ze wskazówkami w temacie ASP.NET Core Blazor WebAssembly z grupami i rolami microsoft Entra ID.
  2. W obszarze ME-ID w witrynie Azure Portal otwórz aplikacje dla przedsiębiorstw.
  3. Wybierz aplikację z listy.
  4. Wybierz pozycję Użytkownicy i grupy.
  5. Wybierz pozycję Dodaj użytkownika/grupę.
  6. Wybierz użytkownika i wybierz swoją rolę w celu uzyskania dostępu do aplikacji. Do użytkownika przypisano wiele ról, powtarzając proces dodawania użytkownika do aplikacji do momentu przypisania wszystkich ról użytkownika. Użytkownicy z wieloma rolami są wyświetlani raz dla każdej przypisanej roli na liście Użytkownicy i grupy użytkowników dla aplikacji.
  7. Wybierz przycisk Przypisz.

DefaultAccessTokenScopes a AdditionalScopesToConsent

Przykłady w tym artykule aprowizować zakresy interfejsu API programu Graph z elementem DefaultAccessTokenScopes, a nie AdditionalScopesToConsent.

AdditionalScopesToConsent nie jest używana, ponieważ nie można aprowizować zakresów interfejsu API programu Graph dla użytkowników podczas pierwszego logowania się do aplikacji przy użyciu biblioteki MSAL za pośrednictwem interfejsu użytkownika zgody platformy Azure. Gdy użytkownik próbuje uzyskać dostęp do interfejsu API programu Graph po raz pierwszy przy użyciu zestawu Graph SDK, jest on skonfrontowany z wyjątkiem:

Microsoft.Graph.Models.ODataErrors.ODataError: Access token is empty.

Gdy użytkownik aprowizuje zakresy interfejsu API programu Graph udostępniane za pośrednictwem DefaultAccessTokenScopesusługi , aplikacja może użyć AdditionalScopesToConsent do późniejszego logowania użytkownika. Jednak zmiana kodu aplikacji nie ma sensu dla aplikacji produkcyjnej, która wymaga okresowego dodawania nowych użytkowników z delegowanymi zakresami programu Graph lub dodawania nowych delegowanych zakresów interfejsu API programu Graph do aplikacji.

Poprzednia dyskusja na temat aprowizacji zakresów dostępu do interfejsu API programu Graph, gdy użytkownik po raz pierwszy loguje się do aplikacji, ma zastosowanie tylko do:

  • Aplikacje, które przyjmują zestaw GRAPH SDK.
  • Aplikacje korzystające z nazwy dla HttpClient dostępu interfejsu API programu Graph, które proszą użytkowników o wyrażenie zgody na zakresy programu Graph podczas pierwszego logowania do aplikacji.

Jeśli używasz nazwy HttpClient , która nie prosi użytkowników o wyrażenie zgody na zakresy programu Graph podczas pierwszego logowania, użytkownicy są przekierowywani do interfejsu użytkownika zgody platformy Azure dla zakresów interfejsu API programu Graph, gdy po raz pierwszy zażądają dostępu do interfejsu API programu Graph za pośrednictwem DelegatingHandler wstępnie skonfigurowanej HttpClientnazwy . Gdy zakresy programu Graph nie są początkowo wyrażane za pomocą nazwanego HttpClient podejścia, ani DefaultAccessTokenScopesAdditionalScopesToConsent nie są wywoływane przez aplikację. Aby uzyskać więcej informacji, zobacz nazwane HttpClient pokrycie w tym artykule.

Rozwiązania hostowane Blazor WebAssembly

Przykłady w tym artykule dotyczą używania zestawu Graph SDK lub nazwanego HttpClient interfejsu API programu Graph bezpośrednio z autonomicznej Blazor WebAssembly aplikacji lub bezpośrednio z Client aplikacji hostowanego Blazor WebAssemblyrozwiązania. Dodatkowym scenariuszem, który nie jest opisany w tym artykule, jest Client aplikacja hostowanego rozwiązania do wywoływania Server aplikacji rozwiązania za pośrednictwem internetowego interfejsu API, a następnie Server aplikacja używa zestawu Graph SDK/interfejsu API do wywoływania programu Microsoft Graph i zwracania danych do Client aplikacji. Chociaż jest to obsługiwane podejście, nie jest ono objęte tym artykułem. Jeśli chcesz przyjąć to podejście:

  • Postępuj zgodnie ze wskazówkami w temacie Wywoływanie internetowego interfejsu API z aplikacji ASP.NET Core Blazor dla aspektów internetowego interfejsu API w zakresie wystawiania żądań do Server aplikacji z Client aplikacji i zwracania danych do Client aplikacji.
  • Postępuj zgodnie ze wskazówkami w podstawowej dokumentacji programu Microsoft Graph, aby użyć zestawu SDK programu Graph z typową aplikacją ASP.NET Core, która w tym scenariuszu jest Server aplikacją rozwiązania. Jeśli używasz Blazor WebAssembly szablonu projektu do tworzenia hostowanego Blazor WebAssembly rozwiązania (ASP.NET Core Hosted/-h|--hosted) z autoryzacją organizacyjną (pojedynczą organizacją lubSingleOrg wieloma organizacjami/MultiOrg) oraz opcją Microsoft Graph (Platforma tożsamości Microsoft> Połączenie ed Services Add Microsoft Graph permissions (Dodaj uprawnienia programu Microsoft Graph)> w programie Visual Studio lub --calls-graph opcji z poleceniem interfejsu wiersza polecenia dotnet newServer platformy .NET aplikacja rozwiązania jest skonfigurowana do używania zestawu Graph SDK podczas tworzenia rozwiązania na podstawie szablonu projektu.

Dodatkowe zasoby

Wskazówki ogólne

  • Dokumentacja programu Microsoft Graph
  • Przykładowa Blazor WebAssembly aplikacja programu Microsoft Graph: w tym przykładzie pokazano, jak używać zestawu MICROSOFT Graph .NET SDK do uzyskiwania dostępu do danych w usłudze Office 365 z Blazor WebAssembly aplikacji.
  • Tworzenie aplikacji .NET przy użyciu samouczka programu Microsoft Graph i przykładowej aplikacji Microsoft Graph ASP.NET Core: chociaż te zasoby nie mają bezpośredniego zastosowania do wywoływania programu Graph z aplikacji po stronieBlazor WebAssembly klienta, konfiguracja aplikacji ME-ID i praktyki kodowania programu Microsoft Graph w połączonych zasobach są istotne dla Blazor WebAssembly autonomicznych aplikacji i powinny być konsultowane z ogólnymi najlepszymi rozwiązaniami.
  • Dokumentacja programu Microsoft Graph
  • Przykładowa Blazor WebAssembly aplikacja programu Microsoft Graph: w tym przykładzie pokazano, jak używać zestawu MICROSOFT Graph .NET SDK do uzyskiwania dostępu do danych w usłudze Office 365 z Blazor WebAssembly aplikacji.
  • Tworzenie aplikacji platformy .NET za pomocą programu Microsoft Graph iprzykładowej aplikacji Microsoft Graph ASP.NET Core: te zasoby są najbardziej odpowiednie dla rozwiązań hostowanychBlazor WebAssembly, w których Server aplikacja jest skonfigurowana do uzyskiwania dostępu do programu Microsoft Graph jako typowej aplikacji ASP.NET Core w imieniu Client aplikacji. Aplikacja Client używa internetowego interfejsu API do podejmowania żądań do Server aplikacji dla danych programu Graph. Chociaż te zasoby nie mają bezpośredniego zastosowania do wywoływania programu Graph z aplikacji po stronieBlazor WebAssembly klienta, konfiguracja aplikacji ME-ID i praktyki kodowania programu Microsoft Graph w połączonych zasobach są istotne dla Blazor WebAssembly autonomicznych aplikacji i powinny być konsultowane z ogólnymi najlepszymi rozwiązaniami.

Wskazówki dotyczące bezpieczeństwa