Delen via


Graph API gebruiken met ASP.NET Core Blazor WebAssembly

Opmerking

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Belangrijk

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

In dit artikel wordt uitgelegd hoe u Microsoft Graph gebruikt in Blazor WebAssembly apps, waarmee apps toegang kunnen krijgen tot Microsoft Cloud-resources.

Er worden twee benaderingen behandeld:

  • Graph SDK: De Microsoft Graph SDK vereenvoudigt het bouwen van hoogwaardige, efficiënte en flexibele apps die toegang hebben tot Microsoft Graph. Selecteer de knop Graph SDK bovenaan dit artikel om deze benadering te gebruiken.

  • Benoemde HttpClient met Graph API: een benoemde HttpClient kan Microsoft Graph API-aanvragen rechtstreeks naar Microsoft Graph uitgeven. Selecteer de knop Benoemde HttpClient met Graph API bovenaan dit artikel om deze benadering te gebruiken.

De richtlijnen in dit artikel zijn niet bedoeld om de Microsoft Graph-documentatie en Azure-beveiligingsrichtlijnen in andere Microsoft-documentatiesets te vervangen. Beoordeel de beveiligingsrichtlijnen in de sectie Aanvullende resources van dit artikel voordat u Microsoft Graph implementeert in een productieomgeving. Volg de aanbevolen procedures van Microsoft om de beveiligingsproblemen van uw apps te beperken.

Aanvullende benaderingen voor het werken met Microsoft Graph en Blazor WebAssembly worden geleverd door de volgende Microsoft Graph- en Azure-voorbeelden:

Als u feedback wilt geven over een van de voorgaande twee voorbeelden, opent u een probleem in de GitHub-opslagplaats van het voorbeeld. Als u een probleem voor het Azure-voorbeeld opent, geeft u een koppeling naar het voorbeeld op in de opmerking bij het openen, omdat de Azure-voorbeeldopslagplaats (Azure-Samples) veel voorbeelden bevat. Beschrijf het probleem in detail en neem indien nodig voorbeeldcode op. Plaats een minimale app in GitHub waarmee het probleem of de fout wordt gereproduceerd. Verwijder de configuratiegegevens van het Azure-account uit het voorbeeld voordat u deze doorvoert naar de openbare opslagplaats.

Als u feedback wilt geven of hulp wilt vragen bij dit artikel of ASP.NET Core, raadpleegt u ASP.NET Basisprincipes van CoreBlazor.

Belangrijk

De scenario's die in dit artikel worden beschreven, zijn van toepassing op het gebruik van Microsoft Entra (ME-ID) als id-provider, niet AAD B2C. Het gebruik van Microsoft Graph met een app aan de clientzijde Blazor WebAssembly en de AAD B2C-id-provider wordt op dit moment niet ondersteund, omdat de app een clientgeheim vereist, dat niet kan worden beveiligd in de client-app Blazor . Voor een zelfstandige Blazor WebAssembly AAD B2C-app gebruikt u Graph API door een backendserver-API te maken voor toegang tot Graph API namens gebruikers. De app aan de clientzijde verifieert en autoriseert gebruikers om de web-API aan te roepen om veilig toegang te krijgen tot Microsoft Graph en gegevens terug te keren naar de app aan de clientzijde Blazor vanuit uw web-API op de server. Het clientgeheim wordt veilig onderhouden in de web-API op de server, niet in de Blazor app op de client. Sla nooit een clientgeheim op in een app aan de clientzijde Blazor .

Het gebruik van een gehoste Blazor WebAssembly app wordt ondersteund, waarbij de Server app de Graph SDK/API gebruikt om Graph-gegevens aan de Client app te verstrekken via web-API. Zie de sectie Gehoste Blazor WebAssembly oplossingen van dit artikel voor meer informatie.

De voorbeelden in dit artikel maken gebruik van nieuwe .NET/C#-functies. Wanneer u de voorbeelden met .NET 7 of eerder gebruikt, zijn kleine wijzigingen vereist. De voorbeelden van tekst en code die betrekking hebben op interactie met Microsoft Graph zijn echter hetzelfde voor alle versies van ASP.NET Core.

De volgende richtlijnen zijn van toepassing op Microsoft Graph v5.

De Microsoft Graph SDK voor gebruik in Blazor apps wordt de Microsoft Graph .NET-clientbibliotheek genoemd.

Voor de Graph SDK-voorbeelden zijn de volgende pakketverwijzingen in de zelfstandige Blazor WebAssembly app vereist. Er wordt al verwezen naar de eerste twee pakketten als de app is ingeschakeld voor MSAL-verificatie, bijvoorbeeld bij het maken van de app door de richtlijnen in Een zelfstandige ASP.NET Core-app Blazor WebAssembly beveiligen met Microsoft Entra-id te volgen.

De Graph SDK-voorbeelden vereisen de volgende pakketverwijzingen in de zelfstandige Blazor WebAssembly app of de Client app van een gehoste Blazor WebAssembly oplossing. Er wordt al verwezen naar de eerste twee pakketten als de app is ingeschakeld voor MSAL-verificatie, bijvoorbeeld bij het maken van de app door de richtlijnen in Een zelfstandige ASP.NET Core-app Blazor WebAssembly beveiligen met Microsoft Entra-id te volgen.

Opmerking

Zie voor richtlijnen over het toevoegen van pakketten aan .NET-apps de artikelen onder Pakketten installeren en beheren in de Package consumption workflow (NuGet-documentatie). Bevestig de juiste pakketversies op NuGet.org.

Verdeel in Azure Portal gedelegeerde machtigingen (bereiken)† voor Microsoft Graph-gegevens waartoe de app namens een gebruiker toegang moet hebben. Voor het voorbeeld in dit artikel moet de registratie van de app gedelegeerde machtigingen bevatten voor het lezen van gebruikersgegevens (Microsoft.Graph>User.Read bereik in API-machtigingen, Type: Gedelegeerd). Met User.Read het bereik kunnen gebruikers zich aanmelden bij de app en kan de app het profiel en de bedrijfsgegevens van aangemelde gebruikers lezen. Zie Overzicht van machtigingen en toestemming in het Microsoft Identity Platform en Overzicht van Microsoft Graph-machtigingenvoor meer informatie.

Permissions en bereiken betekenen hetzelfde en worden door elkaar gebruikt in beveiligingsdocumentatie en Azure Portal. Tenzij de tekst verwijst naar de Azure portal, gebruikt dit artikel -bereik/-bereiken bij het verwijzen naar de Graph-machtigingen.

Scopes zijn niet hoofdlettergevoelig, dus User.Read is hetzelfde als user.read. U kunt beide indelingen gebruiken, maar we raden een consistente keuze aan in toepassingscode.

Nadat u de Microsoft Graph API-bereiken hebt toegevoegd aan de registratie van de app in Azure Portal, voegt u de volgende configuratie van app-instellingen toe aan het wwwroot/appsettings.json bestand in de app, waaronder de Graph-basis-URL met de Microsoft Graph-versie en -bereiken. In het volgende voorbeeld wordt het User.Read bereik opgegeven voor de voorbeelden in latere secties van dit artikel. Scopes zijn niet hoofdlettergevoelig.

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

In het voorgaande voorbeeld is de {VERSION} tijdelijke aanduiding de versie van de Microsoft Graph API (bijvoorbeeld: v1.0).

Hier volgt een voorbeeld van een volledig wwwroot/appsettings.json configuratiebestand voor een app die gebruikmaakt van ME-ID als id-provider, waarbij het lezen van gebruikersgegevens (user.read bereik) is opgegeven voor Microsoft Graph:

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

In het vorige voorbeeld is de {TENANT ID} placeholder de Directory (tenant) ID en de {CLIENT ID} placeholder de Application (client) ID. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Voeg de volgende GraphClientExtensions klasse toe aan de zelfstandige app. De scopes worden toegewezen aan de Scopes eigenschap van de AccessTokenRequestOptions in de AuthenticateRequestAsync methode.

Voeg de volgende GraphClientExtensions klasse toe aan de zelfstandige app of Client app van een gehoste Blazor WebAssemblyoplossing. De scopes worden toegewezen aan de Scopes eigenschap van de AccessTokenRequestOptions in de AuthenticateRequestAsync methode.

Wanneer er geen toegangstoken wordt verkregen, stelt de volgende code geen Bearer-autorisatieheader in voor Graph-aanvragen.

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[]>() ??
                        [ "user.read" ]
                });

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

Belangrijk

Zie de DefaultAccessTokenScopes versus AdditionalScopesToConsent sectie voor een verklaring over waarom de voorgaande code de DefaultAccessTokenScopes bereiken toevoegt in plaats van AdditionalScopesToConsent.

Voeg in het Program bestand de Graph-clientservices en -configuratie toe met de AddGraphClient extensiemethode. De volgende code wordt standaard ingesteld op het Microsoft Graph basisadres van versie 1.0 en scopes als deze instellingen niet worden gevonden in het app-configuratiebestand.

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Graph API aanroepen vanuit een onderdeel met behulp van de Graph SDK

In het volgende UserData-onderdeel wordt gebruik gemaakt van een geïnjecteerde GraphServiceClient om de profielgegevens van de gebruiker ME-ID te verkrijgen en zijn/haar mobiele telefoonnummer weer te geven.

Voor elke testgebruiker die u in ME-ID maakt, moet u ervoor zorgen dat u het ME-ID profiel van de gebruiker een mobiel telefoonnummer in Azure Portal geeft.

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();
    }
}

Voeg een koppeling toe naar de pagina van het onderdeel in het NavMenu onderdeel (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>

Aanbeveling

Als u gebruikers aan een app wilt toevoegen, raadpleegt u de sectie Gebruikers toewijzen aan een app-registratie met of zonder app-rollen .

Bij het lokaal testen met de Graph SDK raden we u aan een nieuwe InPrivate-/incognitobrowsersessie te gebruiken voor elke test om te voorkomen dat achterblijvende cookies storen met tests. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Gebruikersclaims aanpassen met behulp van de Graph SDK

In het volgende voorbeeld maakt de app mobiele telefoonnummers en kantoorlocatieclaims voor een gebruiker op basis van de gegevens van hun ME-ID gebruikersprofiel. Voor de app moet het User.Read Graph API-bereik zijn geconfigureerd in ME-ID. Testgebruikers voor dit scenario moeten beschikken over een mobiel telefoonnummer en kantoorlocatie in hun ME-ID profiel, dat kan worden toegevoegd via Azure Portal.

In de volgende aangepaste gebruikersaccount-aanmaker:

  • Een ILogger (logger) is voor het gemak opgenomen voor het geval u informatie of fouten in de CreateUserAsync methode wilt vastleggen.
  • In het geval dat er een AccessTokenNotAvailableException wordt gegenereerd, wordt de gebruiker omgeleid naar de id-provider om zich aan te melden bij hun account. Er kunnen aanvullende of andere acties worden uitgevoerd wanneer het aanvragen van een toegangstoken mislukt. De app kan bijvoorbeeld het AccessTokenNotAvailableException registreren en een ondersteuningsticket maken voor verder onderzoek.
  • Het framework's RemoteUserAccount vertegenwoordigt het account van de gebruiker. Als voor de app een aangepaste gebruikersaccountklasse is vereist die wordt uitgebreid RemoteUserAccount, wisselt u uw aangepaste gebruikersaccountklasse voor RemoteUserAccount in de volgende code.

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;

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 = string.Join("/",
        config.GetSection("MicrosoftGraph")["BaseUrl"] ?? 
            "https://graph.microsoft.com",
        config.GetSection("MicrosoftGraph")["Version"] ??
            "v1.0");

    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;
    }
}

Configureer de MSAL-verificatie om het custom-factory voor gebruikersaccounts te gebruiken.

Controleer of het Program-bestand gebruikmaakt van de Microsoft.AspNetCore.Components.WebAssembly.Authentication naamruimte:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Het voorbeeld in deze sectie is gebaseerd op de benadering van het lezen van de basis-URL met versie en scopes uit de app-configuratie via de MicrosoftGraph sectie in het wwwroot/appsettings.json bestand. De volgende regels moeten al aanwezig zijn in het Program bestand volgens de richtlijnen eerder in dit artikel:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Zoek in het Program bestand de aanroep naar de AddMsalAuthentication extensiemethode. Werk de code bij naar het volgende, inclusief een aanroep naar AddAccountClaimsPrincipalFactory, die een principal factory voor accountclaims toevoegt met de CustomAccountFactory.

Als de app gebruikmaakt van een aangepaste gebruikersaccountklasse die wordt uitgebreid RemoteUserAccount, wisselt u de aangepaste gebruikersaccountklasse voor RemoteUserAccount in de volgende code.

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

U kunt het volgende UserClaims onderdeel gebruiken om de claims van de gebruiker te bestuderen nadat de gebruiker is geverifieerd met 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;
    }
}

Voeg een koppeling toe naar de pagina van het onderdeel in het NavMenu onderdeel (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>

Bij het lokaal testen met de Graph SDK raden we u aan een nieuwe InPrivate-/incognitobrowsersessie te gebruiken voor elke test om te voorkomen dat achterblijvende cookies storen met tests. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

De volgende richtlijnen zijn van toepassing op Microsoft Graph v4. Als u een app bijwerken van SDK v4 naar v5, raadpleegt u het wijzigingenlogboek en de upgradehandleiding voor Microsoft Graph .NET SDK v5.

De Microsoft Graph SDK voor gebruik in Blazor apps wordt de Microsoft Graph .NET-clientbibliotheek genoemd.

Voor de Graph SDK-voorbeelden zijn de volgende pakketverwijzingen in de zelfstandige Blazor WebAssembly app vereist. Er wordt al verwezen naar de eerste twee pakketten als de app is ingeschakeld voor MSAL-verificatie, bijvoorbeeld bij het maken van de app door de richtlijnen in Een zelfstandige ASP.NET Core-app Blazor WebAssembly beveiligen met Microsoft Entra-id te volgen.

De Graph SDK-voorbeelden vereisen de volgende pakketverwijzingen in de zelfstandige Blazor WebAssembly app of de Client app van een gehoste Blazor WebAssembly oplossing. Er wordt al verwezen naar de eerste twee pakketten als de app is ingeschakeld voor MSAL-verificatie, bijvoorbeeld bij het maken van de app door de richtlijnen in Een zelfstandige ASP.NET Core-app Blazor WebAssembly beveiligen met Microsoft Entra-id te volgen.

Opmerking

Zie voor richtlijnen over het toevoegen van pakketten aan .NET-apps de artikelen onder Pakketten installeren en beheren in de Package consumption workflow (NuGet-documentatie). Bevestig de juiste pakketversies op NuGet.org.

Verdeel in Azure Portal gedelegeerde machtigingen (bereiken)† voor Microsoft Graph-gegevens waartoe de app namens een gebruiker toegang moet hebben. Voor het voorbeeld in dit artikel moet de registratie van de app gedelegeerde machtigingen bevatten voor het lezen van gebruikersgegevens (Microsoft.Graph>User.Read bereik in API-machtigingen, Type: Gedelegeerd). Met User.Read het bereik kunnen gebruikers zich aanmelden bij de app en kan de app het profiel en de bedrijfsgegevens van aangemelde gebruikers lezen. Zie Overzicht van machtigingen en toestemming in het Microsoft Identity Platform en Overzicht van Microsoft Graph-machtigingenvoor meer informatie.

Permissions en bereiken betekenen hetzelfde en worden door elkaar gebruikt in beveiligingsdocumentatie en Azure Portal. Tenzij de tekst verwijst naar de Azure portal, gebruikt dit artikel -bereik/-bereiken bij het verwijzen naar de Graph-machtigingen.

Scopes zijn niet hoofdlettergevoelig, dus User.Read is hetzelfde als user.read. U kunt beide indelingen gebruiken, maar we raden een consistente keuze aan in toepassingscode.

Nadat u de Microsoft Graph API-bereiken hebt toegevoegd aan de registratie van de app in Azure Portal, voegt u de volgende configuratie van app-instellingen toe aan het wwwroot/appsettings.json bestand in de app, waaronder de Graph-basis-URL met de Microsoft Graph-versie en -bereiken. In het volgende voorbeeld wordt het User.Read bereik opgegeven voor de voorbeelden in latere secties van dit artikel. Scopes zijn niet hoofdlettergevoelig.

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

In het voorgaande voorbeeld is de {VERSION} tijdelijke aanduiding de versie van de Microsoft Graph API (bijvoorbeeld: v1.0).

Hier volgt een voorbeeld van een volledig wwwroot/appsettings.json configuratiebestand voor een app die gebruikmaakt van ME-ID als id-provider, waarbij het lezen van gebruikersgegevens (user.read bereik) is opgegeven voor Microsoft Graph:

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

In het vorige voorbeeld is de {TENANT ID} placeholder de Directory (tenant) ID en de {CLIENT ID} placeholder de Application (client) ID. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Voeg de volgende GraphClientExtensions klasse toe aan de zelfstandige app. De scopes worden toegewezen aan de Scopes eigenschap van de AccessTokenRequestOptions in de AuthenticateRequestAsync methode. De IHttpProvider.OverallTimeout waarde wordt uitgebreid van de standaardwaarde van 100 seconden tot 300 seconden, zodat u meer HttpClient tijd krijgt om een antwoord van Microsoft Graph te ontvangen.

Voeg de volgende GraphClientExtensions klasse toe aan de zelfstandige app of Client app van een gehoste Blazor WebAssemblyoplossing. De scopes worden toegewezen aan de Scopes eigenschap van de AccessTokenRequestOptions in de AuthenticateRequestAsync methode. De IHttpProvider.OverallTimeout waarde wordt uitgebreid van de standaardwaarde van 100 seconden tot 300 seconden, zodat u meer HttpClient tijd krijgt om een antwoord van Microsoft Graph te ontvangen.

Wanneer er geen toegangstoken wordt verkregen, stelt de volgende code geen Bearer-autorisatieheader in voor Graph-aanvragen.

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()
        {
        }
    }
}

Belangrijk

Zie de DefaultAccessTokenScopes versus AdditionalScopesToConsent sectie voor een verklaring over waarom de voorgaande code de DefaultAccessTokenScopes bereiken toevoegt in plaats van AdditionalScopesToConsent.

Voeg in het Program bestand de Graph-clientservices en -configuratie toe met de AddGraphClient extensiemethode:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Graph API aanroepen vanuit een onderdeel met behulp van de Graph SDK

In het volgende UserData-onderdeel wordt gebruik gemaakt van een geïnjecteerde GraphServiceClient om de profielgegevens van de gebruiker ME-ID te verkrijgen en zijn/haar mobiele telefoonnummer weer te geven. Voor elke testgebruiker die u in ME-ID maakt, moet u ervoor zorgen dat u het ME-ID profiel van de gebruiker een mobiel telefoonnummer in Azure Portal geeft.

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();
    }
}

Voeg een koppeling toe naar de pagina van het onderdeel in het NavMenu onderdeel (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>

Aanbeveling

Als u gebruikers aan een app wilt toevoegen, raadpleegt u de sectie Gebruikers toewijzen aan een app-registratie met of zonder app-rollen .

Bij het lokaal testen met de Graph SDK raden we u aan een nieuwe InPrivate-/incognitobrowsersessie te gebruiken voor elke test om te voorkomen dat achterblijvende cookies storen met tests. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Gebruikersclaims aanpassen met behulp van de Graph SDK

In het volgende voorbeeld maakt de app mobiele telefoonnummers en kantoorlocatieclaims voor een gebruiker op basis van de gegevens van hun ME-ID gebruikersprofiel. Voor de app moet het User.Read Graph API-bereik zijn geconfigureerd in ME-ID. Testgebruikers voor dit scenario moeten beschikken over een mobiel telefoonnummer en kantoorlocatie in hun ME-ID profiel, dat kan worden toegevoegd via Azure Portal.

In de volgende aangepaste gebruikersaccount-aanmaker:

  • Een ILogger (logger) is voor het gemak opgenomen voor het geval u informatie of fouten in de CreateUserAsync methode wilt vastleggen.
  • In het geval dat er een AccessTokenNotAvailableException wordt gegenereerd, wordt de gebruiker omgeleid naar de id-provider om zich aan te melden bij hun account. Er kunnen aanvullende of andere acties worden uitgevoerd wanneer het aanvragen van een toegangstoken mislukt. De app kan bijvoorbeeld het AccessTokenNotAvailableException registreren en een ondersteuningsticket maken voor verder onderzoek.
  • Het framework's RemoteUserAccount vertegenwoordigt het account van de gebruiker. Als voor de app een aangepaste gebruikersaccountklasse is vereist die wordt uitgebreid RemoteUserAccount, wisselt u uw aangepaste gebruikersaccountklasse voor RemoteUserAccount in de volgende code.

CustomAccountFactory.cs:

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

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;
    }
}

Configureer de MSAL-verificatie om het custom-factory voor gebruikersaccounts te gebruiken.

Controleer of het Program-bestand gebruikmaakt van de Microsoft.AspNetCore.Components.WebAssembly.Authentication naamruimte:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Het voorbeeld in deze sectie is gebaseerd op de benadering van het lezen van de basis-URL met versie en scopes uit de app-configuratie via de MicrosoftGraph sectie in het wwwroot/appsettings.json bestand. De volgende regels moeten al aanwezig zijn in het Program bestand volgens de richtlijnen eerder in dit artikel:

var baseUrl = string.Join("/",
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
        "https://graph.microsoft.com",
    builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
        "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

Zoek in het Program bestand de aanroep naar de AddMsalAuthentication extensiemethode. Werk de code bij naar het volgende, inclusief een aanroep naar AddAccountClaimsPrincipalFactory, die een principal factory voor accountclaims toevoegt met de CustomAccountFactory.

Als de app gebruikmaakt van een aangepaste gebruikersaccountklasse die wordt uitgebreid RemoteUserAccount, wisselt u de aangepaste gebruikersaccountklasse voor RemoteUserAccount in de volgende code.

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

U kunt het volgende UserClaims onderdeel gebruiken om de claims van de gebruiker te bestuderen nadat de gebruiker is geverifieerd met 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;
    }
}

Voeg een koppeling toe naar de pagina van het onderdeel in het NavMenu onderdeel (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>

Bij het lokaal testen met de Graph SDK raden we u aan een nieuwe InPrivate-/incognitobrowsersessie te gebruiken voor elke test om te voorkomen dat achterblijvende cookies storen met tests. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

In de volgende voorbeelden wordt een benoemd label HttpClient voor Graph API-aanroepen gebruikt om het mobiele telefoonnummer van een gebruiker op te halen ter verwerking van een oproep of om de claims van een gebruiker aan te passen en zo een claim voor mobiele telefoonnummers en een claim voor kantoorlocatie op te nemen.

Voor de voorbeelden is een pakketreferentie vereist voor Microsoft.Extensions.Http de zelfstandige Blazor WebAssembly app.

Voor de voorbeelden is een pakketreferentie vereist voor Microsoft.Extensions.Http de zelfstandige Blazor WebAssembly app of de Client app van een gehoste Blazor WebAssembly oplossing.

Opmerking

Zie voor richtlijnen over het toevoegen van pakketten aan .NET-apps de artikelen onder Pakketten installeren en beheren in de Package consumption workflow (NuGet-documentatie). Bevestig de juiste pakketversies op NuGet.org.

Verdeel in Azure Portal gedelegeerde machtigingen (bereiken)† voor Microsoft Graph-gegevens waartoe de app namens een gebruiker toegang moet hebben. Voor het voorbeeld in dit artikel moet de registratie van de app gedelegeerde machtigingen bevatten voor het lezen van gebruikersgegevens (Microsoft.Graph>User.Read bereik in API-machtigingen, Type: Gedelegeerd). Met User.Read het bereik kunnen gebruikers zich aanmelden bij de app en kan de app het profiel en de bedrijfsgegevens van aangemelde gebruikers lezen. Zie Overzicht van machtigingen en toestemming in het Microsoft Identity Platform en Overzicht van Microsoft Graph-machtigingenvoor meer informatie.

Permissions en bereiken betekenen hetzelfde en worden door elkaar gebruikt in beveiligingsdocumentatie en Azure Portal. Tenzij de tekst verwijst naar de Azure portal, gebruikt dit artikel -bereik/-bereiken bij het verwijzen naar de Graph-machtigingen.

Scopes zijn niet hoofdlettergevoelig, dus User.Read is hetzelfde als user.read. U kunt beide indelingen gebruiken, maar we raden een consistente keuze aan in toepassingscode.

Nadat u de Microsoft Graph API-bereiken hebt toegevoegd aan de registratie van de app in Azure Portal, voegt u de volgende configuratie van app-instellingen toe aan het wwwroot/appsettings.json bestand in de app, waaronder de Graph-basis-URL met de Microsoft Graph-versie en -bereiken. In het volgende voorbeeld wordt het User.Read bereik opgegeven voor de voorbeelden in latere secties van dit artikel. Scopes zijn niet hoofdlettergevoelig.

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

In het voorgaande voorbeeld is de {VERSION} tijdelijke aanduiding de versie van de Microsoft Graph API (bijvoorbeeld: v1.0).

Hier volgt een voorbeeld van een volledig wwwroot/appsettings.json configuratiebestand voor een app die gebruikmaakt van ME-ID als id-provider, waarbij het lezen van gebruikersgegevens (user.read bereik) is opgegeven voor Microsoft Graph:

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

In het vorige voorbeeld is de {TENANT ID} placeholder de Directory (tenant) ID en de {CLIENT ID} placeholder de Application (client) ID. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Maak de volgende GraphAuthorizationMessageHandler klasse en projectconfiguratie in het Program bestand voor het werken met Graph API. De basis-URL en scopes worden vanuit de configuratie aan de handler verstrekt.

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: [ 
                string.Join("/",
                    config.GetSection("MicrosoftGraph")["BaseUrl"] ??
                        "https://graph.microsoft.com",
                    config.GetSection("MicrosoftGraph")["Version"] ??
                        "v1.0")
            ],
            scopes: config.GetSection("MicrosoftGraph:Scopes")
                        .Get<List<string>>() ?? [ "user.read" ]);
    }
}

De afsluitende slash (/) van de geautoriseerde URL is vereist. Met de voorgaande code wordt de volgende geautoriseerde URL gemaakt van de configuratie van app-instellingen of wordt standaard ingesteld op de volgende geautoriseerde URL als de configuratie van de app-instellingen ontbreekt: https://graph.microsoft.com/v1.0/

Configureer in het Program bestand de benoemde HttpClient voor Graph API:

builder.Services.AddTransient<GraphAuthorizationMessageHandler>();

builder.Services.AddHttpClient("GraphAPI",
        client => client.BaseAddress = new Uri(
            string.Join("/",
                builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
                    "https://graph.microsoft.com",
                builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
                    "v1.0",
                string.Empty)))
    .AddHttpMessageHandler<GraphAuthorizationMessageHandler>();

In het voorgaande voorbeeld wordt de GraphAuthorizationMessageHandlerDelegatingHandler service geregistreerd als een tijdelijke service voor AddHttpMessageHandler. Tijdelijke registratie wordt aanbevolen voor IHttpClientFactory, waarmee zijn eigen DI-bereiken worden beheerd. Zie de volgende bronnen voor meer informatie:

Er is een afsluitende slash (/) op het basisadres vereist. In de voorgaande code is het derde argument aan string.Joinstring.Empty om ervoor te zorgen dat de afsluitende slash aanwezig is: https://graph.microsoft.com/v1.0/.

Graph API aanroepen vanuit een onderdeel met behulp van een benoemde HttpClient

De UserInfo.cs klasse wijst de vereiste eigenschappen van het gebruikersprofiel aan met het JsonPropertyNameAttribute kenmerk en de JSON-naam die wordt gebruikt door ME-ID. In het volgende voorbeeld worden eigenschappen ingesteld voor het mobiele telefoonnummer en de kantoorlocatie van de gebruiker.

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; }
}

In het volgende UserData onderdeel wordt er een HttpClient gemaakt voor Graph API om een aanvraag uit te voeren voor de profielgegevens van de gebruiker. De me bronnen (me) worden toegevoegd aan de basis-URL inclusief versie voor het Graph API-verzoek. JSON-gegevens die door Graph worden geretourneerd, worden gedeserialiseerd in de UserInfo klasse-eigenschappen. In het volgende voorbeeld wordt het mobiele telefoonnummer verkregen. Je kunt vergelijkbare code toevoegen om de kantoorlocatie van de gebruiker ME-ID op te nemen als je dat wilt (userInfo.OfficeLocation). Als de aanvraag voor het toegangstoken mislukt, wordt de gebruiker omgeleid om zich aan te melden bij de app voor een nieuw toegangstoken.

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();
        }
    }
}

Voeg een koppeling toe naar de pagina van het onderdeel in het NavMenu onderdeel (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>

Aanbeveling

Als u gebruikers aan een app wilt toevoegen, raadpleegt u de sectie Gebruikers toewijzen aan een app-registratie met of zonder app-rollen .

In de volgende reeks wordt de nieuwe gebruikersstroom voor Graph API-bereiken beschreven:

  1. De nieuwe gebruiker meldt zich voor het eerst aan bij de app.
  2. De gebruiker stemt in met het gebruik van de app in de gebruikersinterface van Azure-toestemming.
  3. De gebruiker opent een onderdeelpagina die Graph API-gegevens voor het eerst aanvraagt.
  4. De gebruiker wordt omgeleid naar de Gebruikersinterface van Azure-toestemming om toestemming te geven voor Graph API-bereiken.
  5. Graph API-gebruikersgegevens worden geretourneerd.

Als u wilt dat de bereikconfiguratie (toestemming voor de Graph API-bereiken) plaatsvindt bij de eerste aanmelding, geeft u de bereiken voor MSAL-verificatie op als standaardwaarden voor toegangstokens in het bestand Program:

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

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

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

Belangrijk

Zie de DefaultAccessTokenScopes versus AdditionalScopesToConsent sectie voor een verklaring over waarom de voorgaande code de DefaultAccessTokenScopes bereiken toevoegt in plaats van AdditionalScopesToConsent.

Wanneer de voorgaande wijzigingen in de app worden aangebracht, wordt de volgende volgorde door de gebruikersstroom gebruikt:

  1. De nieuwe gebruiker meldt zich voor het eerst aan bij de app.
  2. De gebruiker stemt in met het gebruik van de app- en Graph API-bereiken in de gebruikersinterface van Azure-toestemming.
  3. De gebruiker opent een onderdeelpagina die Graph API-gegevens voor het eerst aanvraagt.
  4. Graph API-gebruikersgegevens worden geretourneerd.

Wanneer u lokaal met de Graph API test, raden we u aan om voor elke test een nieuwe InPrivate-/incognito-browsersessie te gebruiken om te voorkomen dat achterblijvende cookies het testen verstoren. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Gebruikersclaims aanpassen met behulp van een specifieke HttpClient

In het volgende voorbeeld maakt de app een claim voor het mobiele telefoonnummer en een voor de kantoorlocatie van de gebruiker, gebaseerd op de gegevens van hun ME-ID-gebruikersprofiel. Voor de app moet het User.Read Graph API-bereik zijn geconfigureerd in ME-ID. Testgebruikersaccounts in ME-ID een vermelding vereisen voor het mobiele telefoonnummer en de kantoorlocatie, die via Azure Portal aan hun gebruikersprofielen kunnen worden toegevoegd.

Als u de klasse nog niet aan de UserInfo app hebt toegevoegd door de richtlijnen eerder in dit artikel te volgen, voegt u de volgende klasse toe en wijst u de vereiste eigenschappen van het gebruikersprofiel aan met het JsonPropertyNameAttribute kenmerk en de JSON-naam die door ME-ID wordt gebruikt. In het volgende voorbeeld worden eigenschappen ingesteld voor het mobiele telefoonnummer en de kantoorlocatie van de gebruiker.

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; }
}

In de volgende aangepaste gebruikersaccount-aanmaker:

  • Een ILogger (logger) is voor het gemak opgenomen voor het geval u informatie of fouten in de CreateUserAsync methode wilt vastleggen.
  • In het geval dat er een AccessTokenNotAvailableException wordt gegenereerd, wordt de gebruiker omgeleid naar de id-provider om zich aan te melden bij hun account. Er kunnen aanvullende of andere acties worden uitgevoerd wanneer het aanvragen van een toegangstoken mislukt. De app kan bijvoorbeeld het AccessTokenNotAvailableException registreren en een ondersteuningsticket maken voor verder onderzoek.
  • Het framework's RemoteUserAccount vertegenwoordigt het account van de gebruiker. Als voor de app een aangepaste gebruikersaccountklasse is vereist die wordt uitgebreid RemoteUserAccount, wisselt u de aangepaste gebruikersaccountklasse voor RemoteUserAccount in de volgende code.

CustomAccountFactory.cs:

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

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;
    }
}

De MSAL-verificatie is zo geconfigureerd dat het gebruikmaakt van de factory voor aangepaste gebruikersaccounts. Begin door te bevestigen dat het Program bestand gebruikmaakt van de Microsoft.AspNetCore.Components.WebAssembly.Authentication naamruimte:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Zoek in het Program bestand de aanroep naar de AddMsalAuthentication extensiemethode. Werk de code bij naar het volgende, inclusief een aanroep naar AddAccountClaimsPrincipalFactory, die een principal factory voor accountclaims toevoegt met de CustomAccountFactory.

Als de app een aangepaste gebruikersaccountklasse gebruikt die RemoteUserAccount uitbreidt, vervang dan de aangepaste gebruikersaccountklasse van uw app door RemoteUserAccount in de volgende code.

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

Het voorgaande voorbeeld is bedoeld voor een app die gebruikmaakt van ME-ID-verificatie met MSAL. Er bestaan vergelijkbare patronen voor OIDC- en API-verificatie. Zie de voorbeelden in het gedeelte 'De gebruiker aanpassen met een nettoladingclaim' van het artikel over aanvullende beveiligingsscenario's van ASP.NET CoreBlazor WebAssembly.

U kunt het volgende UserClaims onderdeel gebruiken om de claims van de gebruiker te bestuderen nadat de gebruiker is geverifieerd met 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;
    }
}

Voeg een koppeling toe naar de pagina van het onderdeel in het NavMenu onderdeel (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>

Wanneer u lokaal met de Graph API test, raden we u aan om voor elke test een nieuwe InPrivate-/incognito-browsersessie te gebruiken om te voorkomen dat achterblijvende cookies het testen verstoren. Zie Een ASP.NET Core Blazor WebAssembly zelfstandige app beveiligen met Microsoft Entra IDvoor meer informatie.

Gebruikers toewijzen aan een app-registratie met of zonder app-rollen

U kunt gebruikers toevoegen aan een app-registratie en rollen toewijzen aan gebruikers met de volgende stappen in Azure Portal.

Als u een gebruiker wilt toevoegen, selecteert u Gebruikers in het ME-ID gebied van Azure Portal:

  1. Selecteer Nieuwe gebruiker>Nieuwe gebruiker maken.
  2. Gebruik de sjabloon Gebruiker maken .
  3. Geef de gegevens van de gebruiker op in het Identity gebied.
  4. U kunt een eerste wachtwoord genereren of een initiële wachtwoord toewijzen dat de gebruiker wijzigt wanneer deze zich voor de eerste keer aanmeldt. Als u het wachtwoord gebruikt dat door de portal is gegenereerd, noteert u het nu.
  5. Selecteer Maken om de gebruiker te maken. Wanneer Nieuwe gebruikersinterface maken wordt gesloten, selecteert u Vernieuwen om de gebruikerslijst bij te werken en de nieuwe gebruiker weer te geven.
  6. Wijs voor de voorbeelden in dit artikel een mobiel telefoonnummer toe aan de nieuwe gebruiker door hun naam te selecteren in de lijst met gebruikers, eigenschappen te selecteren en de contactgegevens te bewerken om een mobiel telefoonnummer op te geven.

Gebruikers zonder app-rollen aan de app toewijzen:

  1. Open Enterprise-toepassingen in het ME-ID gebied van Azure Portal.
  2. Selecteer de app in de lijst.
  3. Selecteer Gebruikers en groepen.
  4. Selecteer Gebruiker/groep toevoegen.
  5. Selecteer een gebruiker.
  6. Selecteer de knop Toewijzen .

Gebruikers toewijzen aan de app met applicatierollen:

  1. Voeg rollen toe aan de registratie van de app in Azure Portal volgens de richtlijnen in ASP.NET Core Blazor WebAssembly met Microsoft Entra ID-groepen en -rollen.
  2. Open Enterprise-toepassingen in het ME-ID gebied van Azure Portal.
  3. Selecteer de app in de lijst.
  4. Selecteer Gebruikers en groepen.
  5. Selecteer Gebruiker/groep toevoegen.
  6. Selecteer een gebruiker en selecteer de rol voor toegang tot de app. Meerdere rollen worden toegewezen aan een gebruiker door het proces van het toevoegen van de gebruiker aan de app te herhalen totdat alle rollen voor een gebruiker zijn toegewezen. Gebruikers met meerdere rollen worden één keer weergegeven voor elke toegewezen rol in de lijst Gebruikers en groepen met gebruikers voor de app.
  7. Selecteer de knop Toewijzen .

DefaultAccessTokenScopes tegen AdditionalScopesToConsent

In de voorbeelden in dit artikel worden Graph API-bereiken ingericht met DefaultAccessTokenScopes, niet AdditionalScopesToConsent.

AdditionalScopesToConsent wordt niet gebruikt omdat het geen Graph API-bereiken kan inrichten voor gebruikers wanneer ze zich voor het eerst met MSAL aanmelden bij de app via de gebruikersinterface van Azure-toestemming. Wanneer de gebruiker voor het eerst probeert toegang te krijgen tot Graph API met de Graph SDK, wordt deze geconfronteerd met een uitzondering:

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

Nadat een gebruiker Graph API-reikwijdten heeft toegevoegd via DefaultAccessTokenScopes, kan de app AdditionalScopesToConsent gebruiken voor een volgende gebruiker die zich aanmeldt. Het wijzigen van app-code is echter niet logisch voor een productie-app waarvoor de periodieke toevoeging van nieuwe gebruikers met gedelegeerde Graph-bereiken of het toevoegen van nieuwe gedelegeerde Graph API-bereiken aan de app is vereist.

De voorgaande discussie over het instellen van scopes voor Graph API-toegang wanneer een gebruiker zich voor het eerst aanmeldt bij de app, is alleen van toepassing op:

  • Apps die gebruikmaken van de Graph SDK.
  • Apps die gebruikmaken van een benoemde HttpClient Graph API-toegang waarin gebruikers wordt gevraagd om toestemming te geven voor Graph-bereiken bij hun eerste aanmelding bij de app.

Wanneer u een benoemde HttpClient gebruikt die geen toestemming vraagt aan gebruikers voor Graph-scopes bij hun eerste aanmelding, worden gebruikers omgeleid naar de Azure-toestemmings-UI voor toestemming voor Graph API-scopes wanneer ze voor het eerst toegang tot de Graph API aanvragen via de DelegatingHandler van de vooraf geconfigureerde, benoemde HttpClient. Wanneer Graph-bereiken in eerste instantie niet worden toegestaan met de benoemde HttpClient benadering, worden noch DefaultAccessTokenScopes noch AdditionalScopesToConsent door de app aangeroepen. Zie de benoemde HttpClient dekking in dit artikel voor meer informatie.

Gehoste Blazor WebAssembly oplossingen

De voorbeelden in dit artikel hebben betrekking op het gebruik van de Graph SDK of een benoemde HttpClient met Graph API rechtstreeks vanuit een zelfstandige Blazor WebAssembly app of rechtstreeks vanuit de Client app van een gehoste Blazor WebAssemblyoplossing. Een extra scenario dat niet in dit artikel wordt behandeld, is bedoeld voor een Client app van een gehoste oplossing om de app van de Server oplossing aan te roepen via web-API. Vervolgens gebruikt de Server app de Graph SDK/API om Microsoft Graph aan te roepen en gegevens naar de Client app te retourneren. Hoewel dit een ondersteunde benadering is, wordt deze niet behandeld in dit artikel. Als u deze aanpak wilt aannemen:

  • Volg de richtlijnen in Een web-API aanroepen vanuit een ASP.NET Core-app Blazor voor de web-API-aspecten bij het uitgeven van aanvragen aan de app vanuit de ServerClient app en het retourneren van gegevens naar de Client app.
  • Volg de richtlijnen in de primaire Microsoft Graph-documentatie om de Graph SDK te gebruiken met een typische ASP.NET Core-app, die in dit scenario de Server app van de oplossing is. Als u de Blazor WebAssembly projectsjabloon gebruikt om de gehoste Blazor WebAssembly oplossing te maken (ASP.NET Core Gehost/-h|--hosted) met organisatieautorisatie (enkele organisatie/SingleOrg of meerdere organisaties/MultiOrg) en de Microsoft Graph-optie (Microsoft Identity Platform>Connected Services>Microsoft Graph-machtigingen toevoegen in Visual Studio of de --calls-graph optie met de .NET CLI-opdracht dotnet new), dan wordt de app van de oplossing geconfigureerd om de Graph SDK te gebruiken wanneer de oplossing uit de projectsjabloon wordt gemaakt.

Aanvullende bronnen

Algemene richtlijnen

  • Microsoft Graph-documentatie
  • Microsoft Graph-voorbeeld-appBlazor WebAssembly: In dit voorbeeld ziet u hoe u de Microsoft Graph .NET SDK gebruikt voor toegang tot gegevens in Office 365 vanuit Blazor WebAssembly apps.
  • .NET-apps bouwen met Microsoft Graph-zelfstudie en Microsoft Graph-voorbeeld-ASP.NET Core-app: deze resources zijn het meest geschikt voor gehosteBlazor WebAssembly oplossingen, waarbij de Server app is geconfigureerd voor toegang tot Microsoft Graph als een typische ASP.NET Core-app namens de Client app. De Client app maakt gebruik van web-API om aanvragen naar de Server app voor Graph-gegevens te verzenden. Hoewel deze resources niet rechtstreeks van toepassing zijn op het aanroepen van Graph vanuit apps aan de clientzijdeBlazor WebAssembly , zijn de ME-ID app-configuratie- en Microsoft Graph-coderingsprocedures in de gekoppelde resources relevant voor zelfstandige Blazor WebAssembly apps en moeten worden geraadpleegd voor algemene aanbevolen procedures.

Beveiligingsrichtlijnen