Partager via


Utiliser l’API Graph avec ASP.NET Core Blazor WebAssembly

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 8 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la Stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 8 de cet article.

Cet article explique comment utiliser Microsoft API Graph dans les applications Blazor WebAssembly, qui permet aux applications d’accéder aux ressources Microsoft Cloud.

Deux approches sont abordées :

  • SDK Graph : le SDK Microsoft Graph simplifie la création d’applications de haute qualité, efficaces et résilientes qui accèdent à Microsoft Graph. Sélectionnez le bouton SDK Graph en haut de cet article pour adopter cette approche.

  • HttpClient nommé avec l’API Graph : un HttpClient nommé peut émettre des requêtes d’API Microsoft Graph pour accéder directement à Microsoft Graph. Sélectionnez le bouton HttpClient nommé avec l’API Graph en haut de cet article pour adopter cette approche.

Les instructions de cet article ne sont pas destinées à remplacer la documentation Microsoft Graph et des conseils de sécurité Azure dans d’autres ensembles de documentation Microsoft. Évaluez les conseils de sécurité dans la section Ressources supplémentaires de cet article avant d’implémenter Microsoft Graph dans un environnement de production. Suivez les meilleures pratiques de Microsoft pour limiter les vulnérabilités de vos applications.

Des approches supplémentaires pour l’utilisation de Microsoft Graph et Blazor WebAssembly sont fournies par les exemples Microsoft Graph et Azure suivants :

Pour fournir des commentaires sur l’un des deux exemples précédents, ouvrez un problème sur le référentiel GitHub de l’exemple. Si vous ouvrez un problème pour l’exemple Azure, fournissez un lien vers l’exemple dans votre commentaire d’ouverture, car l’exemple de référentiel Azure (Azure-Samples) contient de nombreux exemples. Décrivez le problème en détail et incluez l’exemple de code en fonction des besoins. Placez une application minimale dans GitHub qui reproduit le problème ou l’erreur. Veillez à supprimer les données de configuration de compte Azure de l’exemple avant de le valider dans le référentiel public.

Pour fournir des commentaires ou obtenir de l’aide sur cet article ou ASP.NET Core, consultez Notions de base d’ASP.NET Core Blazor.

Important

Les scénarios décrits dans cet article s’appliquent à l’utilisation de Microsoft Entra (ME-ID) comme fournisseur d’identity, et non AAD B2C. L’utilisation de Microsoft Graph avec une application Blazor WebAssembly côté client et le fournisseur d’identity AAD B2C n’est pas prise en charge pour l’instant, car l’application nécessite alors une clé secrète client qui ne peut pas être sécurisée dans l’application Blazor côté client. Pour qu’une application Blazor WebAssembly autonome AAD B2C utilise l’API Graph, créez une API serveur principal (web) pour accéder à l’API Graph pour le compte des utilisateurs. L’application côté client authentifie et autorise les utilisateurs à appeler l’API web pour accéder en toute sécurité à Microsoft Graph et retourner des données à l’application Blazor côté client depuis votre API web basée sur un serveur. La clé secrète client est conservée en toute sécurité dans l’API web basée sur le serveur, pas dans l’application Blazor côté client. Ne stockez jamais de clé secrète client dans une application Blazor côté client.

L’utilisation d’une application hébergée Blazor WebAssembly est prise en charge, où l’application Server utilise le SDK/API Graph pour fournir des données Graph à l’application via l’API Client web. Pour plus d’informations, consultez la section Solutions de partenairesBlazor WebAssembly dans cet article.

Les exemples de cet article tirent parti des nouvelles fonctionnalités .NET/C#. Lors de l’utilisation des exemples avec .NET 7 ou antérieur, des modifications mineures sont requises. Toutefois, les exemples de texte et de code relatifs à l’interaction avec Microsoft Graph sont identiques pour toutes les versions de ASP.NET Core.

Les instructions suivantes s’appliquent à Microsoft Graph v5.

Le Kit de développement logiciel (SDK) Microsoft Graph à utiliser dans les applications Blazor est appelé bibliothèque cliente Microsoft Graph .NET.

Les exemples du kit de développement logiciel (SDK) Graph nécessitent les références de package suivantes dans l’application Blazor WebAssembly autonome. Les deux premiers packages sont déjà référencés si l’application a été activée pour l’authentification MSAL, par exemple pendant la création de l’application au moyen des instructions fournies dans Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Les exemples de kit de développement logiciel (SDK) Graph nécessitent les références de package suivantes dans l’application Blazor WebAssembly autonome ou l’application Client d’une solution Blazor WebAssembly hébergée. Les deux premiers packages sont déjà référencés si l’application a été activée pour l’authentification MSAL, par exemple pendant la création de l’application au moyen des instructions fournies dans Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Remarque

Pour obtenir des conseils sur l’ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Dans le Portail Azure, accordez des permissions déléguées (étendues)† pour les données Microsoft Graph auxquelles l’application doit pouvoir accéder pour le compte d’un utilisateur. Pour l’exemple de cet article, l’inscription de l’application doit comprendre une autorisation déléguée de lire les données utilisateur (Microsoft.Graph>User.Read étendue dans les autorisations d’API, Type : Délégué). L’étendue User.Read permet aux utilisateurs à se connecter à l’application, mais également à l’application à lire le profil et les informations sur la société des utilisateurs connectés. Pour plus d’informations, consultez Vue d’ensemble des autorisations et du consentement dans la plateforme identity Microsoft et Vue d’ensemble des autorisations Microsoft Graph.

Permissions et étendues signifient la même chose et sont interchangeables dans la documentation de sécurité et dans le Portail Azure. Sauf si le texte fait référence au portail Azure, cet article utilise étendue/étendues pour désigner les autorisations Graph.

Les étendues ne respectent pas la casse, User.Read est donc la même chose que user.read. N’hésitez pas à utiliser l’un ou l’autre format, mais nous vous recommandons de faire preuve de cohérence dans le code de l’application.

Après avoir ajouté les étendues de l’API Microsoft Graph dans l’inscription de l’application dans le Portail Azure, ajoutez la configuration suivante des paramètres d’application au fichier wwwroot/appsettings.json. Ce dernier contient l’URL de base Graph avec la version et les étendues graph. Dans l’exemple suivant, l’étendue User.Read est spécifiée pour les exemples dans les sections ultérieures de cet article. Les étendues ne respectent pas la casse.

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

Dans l’exemple précédent, l’espace réservé {VERSION} est la version de l’API Microsoft Graph (par exemple : v1.0).

Voici un exemple de fichier de configuration wwwroot/appsettings.json complet pour une application qui utilise ME-ID comme fournisseur d’identity, dans lequel la lecture des données utilisateur (étendue user.read) est spécifiée pour 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"
    ]
  }
}

Dans l’exemple précédent, l’espace réservé {TENANT ID} est l’ID de l’annuaire (locataire), tandis que l’espace réservé {CLIENT ID} est l’ID de l’application (client). Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Ajoutez la classe suivante GraphClientExtensions à l’application autonome. Les étendues sont fournies à la propriété Scopes de l' AccessTokenRequestOptions dans la méthode AuthenticateRequestAsync .

Ajoutez la classe GraphClientExtensions suivante à l’application autonome ou à l’application Client d’une solution de Blazor WebAssemblyhébergée. Les étendues sont fournies à la propriété Scopes de l' AccessTokenRequestOptions dans la méthode AuthenticateRequestAsync .

Lorsqu’un jeton d’accès n’est pas obtenu, le code suivant ne définit pas d’en-tête d’autorisation du porteur pour les requêtes 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[]>() ??
                        [ "user.read" ]
                });

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

Important

Consultez la section DefaultAccessTokenScopes plutôt que AdditionalScopesToConsent pour obtenir une explication sur la raison pour laquelle le code précédent utilise DefaultAccessTokenScopes (plutôt que AdditionalScopesToConsent) pour ajouter les étendues.

Dans le fichier Program, ajoutez les services clients et la configuration avec la méthode d’extension AddGraphClient. Le code suivant est défini par défaut sur l’adresse de base de la version 1.0 de Microsoft Graph et les étendues User.Read si ces paramètres ne sont pas trouvés dans le fichier de paramètres de l’application :

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

Appeler l’API Graph à partir d’un composant à l’aide du Kit de développement logiciel (SDK) Graph

Le composant UserData suivant utilise un GraphServiceClient injecté pour obtenir les données de profil ME-ID de l’utilisateur et afficher son numéro de téléphone mobile.

Pour tout utilisateur de test que vous créez dans ME-ID, veillez à donner au profil ME-ID de l’utilisateur un numéro de téléphone mobile dans le portail Azure.

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

Ajoutez un lien vers la page du composant dans le composant 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>

Conseil

Pour ajouter des utilisateurs à une application, consultez la section Attribuer des utilisateurs à une inscription d’application, avec ou sans rôles d’application.

Lorsque vous effectuez des tests en local avec le kit de développement logiciel (SDK) Graph, nous vous recommandons d’utiliser une nouvelle session de navigateur privée/incognito pour chaque test afin d’éviter que les cookies persistants n’interfèrent avec les tests. Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Personnaliser les revendications utilisateur à l’aide du Kit de développement logiciel (SDK) Graph

Dans l’exemple suivant, l’application crée un numéro de téléphone mobile et des revendications d’emplacement de bureau pour un utilisateur à partir des données de son profil utilisateur ME-ID. L’application doit avoir l’étendue de l’API Graph User.Read configurée dans ME-ID. Tous les utilisateurs de test pour ce scénario doivent avoir un numéro de téléphone mobile et un emplacement de bureau dans leur profil ME-ID, qui peut être ajouté via le portail Azure.

Dans la fabrique de compte d’utilisateur personnalisée suivante :

  • Un ILogger (logger) est inclus pour des raisons pratiques au cas où vous souhaitez consigner des informations ou des erreurs dans la méthode CreateUserAsync.
  • Si une exception AccessTokenNotAvailableException est renvoyée, l’utilisateur est redirigé vers le fournisseur d’identity pour se connecter à son compte. Des actions supplémentaires ou différentes peuvent être effectuées lors de l’échec de la requête d’un jeton d’accès. Par exemple, l’application peut enregistrer le AccessTokenNotAvailableException et créer un ticket de support pour une investigation plus approfondie.
  • Le framework RemoteUserAccount représente le compte de l’utilisateur. Si l’application nécessite une classe de compte d’utilisateur personnalisée qui étend RemoteUserAccount, changez votre classe de compte d’utilisateur personnalisée pour RemoteUserAccount dans le code suivant.

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

Configurez l’authentification MSAL pour utiliser la fabrique de compte d’utilisateur personnalisée.

Vérifiez que le fichier Program utilise l’espace de noms Microsoft.AspNetCore.Components.WebAssembly.Authentication :

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

L’exemple de cette section s’appuie sur l’approche de lecture de l’URL de base avec la version et les étendues de la configuration d’application via la section MicrosoftGraph dans le fichierwwwroot/appsettings.json. Les lignes suivantes doivent déjà être présentes dans le fichier Program après avoir suivi les instructions décrites plus haut dans cet article :

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

Dans le fichier Program, recherchez l’appel à la méthode d’extension AddMsalAuthentication. Mettez à jour le code suivant, ce qui inclut un appel à AddAccountClaimsPrincipalFactory qui ajoute une fabrique de principal de revendications de compte avec le CustomAccountFactory.

Si l’application utilise une classe de compte d’utilisateur personnalisée qui s’étend RemoteUserAccount, changez la classe de compte d’utilisateur personnalisée pour RemoteUserAccount dans le code suivant.

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

Vous pouvez utiliser le composant UserClaims suivant pour étudier les revendications de l’utilisateur après l’authentification de l’utilisateur avec 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;
    }
}

Ajoutez un lien vers la page du composant dans le composant 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>

Lorsque vous effectuez des tests en local avec le kit de développement logiciel (SDK) Graph, nous vous recommandons d’utiliser une nouvelle session de navigateur privée/incognito pour chaque test afin d’éviter que les cookies persistants n’interfèrent avec les tests. Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Les instructions suivantes s’appliquent à Microsoft Graph v4. Si vous mettez à niveau une application du SDK v4 vers v5, consultez le journal des modifications et le guide de mise à niveau du Kit de développement logiciel (SDK) .NET Microsoft Graph v5.

Le Kit de développement logiciel (SDK) Microsoft Graph à utiliser dans les applications Blazor est appelé bibliothèque cliente Microsoft Graph .NET.

Les exemples du kit de développement logiciel (SDK) Graph nécessitent les références de package suivantes dans l’application Blazor WebAssembly autonome. Les deux premiers packages sont déjà référencés si l’application a été activée pour l’authentification MSAL, par exemple pendant la création de l’application au moyen des instructions fournies dans Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Les exemples de kit de développement logiciel (SDK) Graph nécessitent les références de package suivantes dans l’application Blazor WebAssembly autonome ou l’application Client d’une solution Blazor WebAssembly hébergée. Les deux premiers packages sont déjà référencés si l’application a été activée pour l’authentification MSAL, par exemple pendant la création de l’application au moyen des instructions fournies dans Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Remarque

Pour obtenir des conseils sur l’ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Dans le Portail Azure, accordez des permissions déléguées (étendues)† pour les données Microsoft Graph auxquelles l’application doit pouvoir accéder pour le compte d’un utilisateur. Pour l’exemple de cet article, l’inscription de l’application doit comprendre une autorisation déléguée de lire les données utilisateur (Microsoft.Graph>User.Read étendue dans les autorisations d’API, Type : Délégué). L’étendue User.Read permet aux utilisateurs à se connecter à l’application, mais également à l’application à lire le profil et les informations sur la société des utilisateurs connectés. Pour plus d’informations, consultez Vue d’ensemble des autorisations et du consentement dans la plateforme identity Microsoft et Vue d’ensemble des autorisations Microsoft Graph.

Permissions et étendues signifient la même chose et sont interchangeables dans la documentation de sécurité et dans le Portail Azure. Sauf si le texte fait référence au portail Azure, cet article utilise étendue/étendues pour désigner les autorisations Graph.

Les étendues ne respectent pas la casse, User.Read est donc la même chose que user.read. N’hésitez pas à utiliser l’un ou l’autre format, mais nous vous recommandons de faire preuve de cohérence dans le code de l’application.

Après avoir ajouté les étendues de l’API Microsoft Graph dans l’inscription de l’application dans le Portail Azure, ajoutez la configuration suivante des paramètres d’application au fichier wwwroot/appsettings.json. Ce dernier contient l’URL de base Graph avec la version et les étendues graph. Dans l’exemple suivant, l’étendue User.Read est spécifiée pour les exemples dans les sections ultérieures de cet article. Les étendues ne respectent pas la casse.

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

Dans l’exemple précédent, l’espace réservé {VERSION} est la version de l’API Microsoft Graph (par exemple : v1.0).

Voici un exemple de fichier de configuration wwwroot/appsettings.json complet pour une application qui utilise ME-ID comme fournisseur d’identity, dans lequel la lecture des données utilisateur (étendue user.read) est spécifiée pour 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"
    ]
  }
}

Dans l’exemple précédent, l’espace réservé {TENANT ID} est l’ID de l’annuaire (locataire), tandis que l’espace réservé {CLIENT ID} est l’ID de l’application (client). Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Ajoutez la classe suivante GraphClientExtensions à l’application autonome. Les étendues sont fournies à la propriété Scopes de l' AccessTokenRequestOptions dans la méthode AuthenticateRequestAsync . Le IHttpProvider.OverallTimeout est étendu depuis la valeur par défaut de 100 secondes à 300 secondes pour donner plus de temps au HttpClient pour recevoir une réponse de Microsoft Graph.

Ajoutez la classe GraphClientExtensions suivante à l’application autonome ou à l’application Client d’une solution de Blazor WebAssemblyhébergée. Les étendues sont fournies à la propriété Scopes de l' AccessTokenRequestOptions dans la méthode AuthenticateRequestAsync . Le IHttpProvider.OverallTimeout est étendu depuis la valeur par défaut de 100 secondes à 300 secondes pour donner plus de temps au HttpClient pour recevoir une réponse de Microsoft Graph.

Lorsqu’un jeton d’accès n’est pas obtenu, le code suivant ne définit pas d’en-tête d’autorisation du porteur pour les requêtes 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()
        {
        }
    }
}

Important

Consultez la section DefaultAccessTokenScopes plutôt que AdditionalScopesToConsent pour obtenir une explication sur la raison pour laquelle le code précédent utilise DefaultAccessTokenScopes (plutôt que AdditionalScopesToConsent) pour ajouter les étendues.

Dans le fichier Program, ajoutez les services clients et la configuration Graph avec la méthode d’extension AddGraphClient :

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

Appeler l’API Graph à partir d’un composant à l’aide du Kit de développement logiciel (SDK) Graph

Le composant UserData suivant utilise un GraphServiceClient injecté pour obtenir les données de profil ME-ID de l’utilisateur et afficher son numéro de téléphone mobile. Pour tout utilisateur de test que vous créez dans ME-ID, veillez à donner au profil ME-ID de l’utilisateur un numéro de téléphone mobile dans le portail Azure.

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

Ajoutez un lien vers la page du composant dans le composant 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>

Conseil

Pour ajouter des utilisateurs à une application, consultez la section Attribuer des utilisateurs à une inscription d’application, avec ou sans rôles d’application.

Lorsque vous effectuez des tests en local avec le kit de développement logiciel (SDK) Graph, nous vous recommandons d’utiliser une nouvelle session de navigateur privée/incognito pour chaque test afin d’éviter que les cookies persistants n’interfèrent avec les tests. Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Personnaliser les revendications utilisateur à l’aide du Kit de développement logiciel (SDK) Graph

Dans l’exemple suivant, l’application crée un numéro de téléphone mobile et des revendications d’emplacement de bureau pour un utilisateur à partir des données de son profil utilisateur ME-ID. L’application doit avoir l’étendue de l’API Graph User.Read configurée dans ME-ID. Tous les utilisateurs de test pour ce scénario doivent avoir un numéro de téléphone mobile et un emplacement de bureau dans leur profil ME-ID, qui peut être ajouté via le portail Azure.

Dans la fabrique de compte d’utilisateur personnalisée suivante :

  • Un ILogger (logger) est inclus pour des raisons pratiques au cas où vous souhaitez consigner des informations ou des erreurs dans la méthode CreateUserAsync.
  • Si une exception AccessTokenNotAvailableException est renvoyée, l’utilisateur est redirigé vers le fournisseur d’identity pour se connecter à son compte. Des actions supplémentaires ou différentes peuvent être effectuées lors de l’échec de la requête d’un jeton d’accès. Par exemple, l’application peut enregistrer le AccessTokenNotAvailableException et créer un ticket de support pour une investigation plus approfondie.
  • Le framework RemoteUserAccount représente le compte de l’utilisateur. Si l’application nécessite une classe de compte d’utilisateur personnalisée qui étend RemoteUserAccount, changez votre classe de compte d’utilisateur personnalisée pour RemoteUserAccount dans le code suivant.

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

Configurez l’authentification MSAL pour utiliser la fabrique de compte d’utilisateur personnalisée.

Vérifiez que le fichier Program utilise l’espace de noms Microsoft.AspNetCore.Components.WebAssembly.Authentication :

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

L’exemple de cette section s’appuie sur l’approche de lecture de l’URL de base avec la version et les étendues de la configuration d’application via la section MicrosoftGraph dans le fichierwwwroot/appsettings.json. Les lignes suivantes doivent déjà être présentes dans le fichier Program après avoir suivi les instructions décrites plus haut dans cet article :

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

Dans le fichier Program, recherchez l’appel à la méthode d’extension AddMsalAuthentication. Mettez à jour le code suivant, ce qui inclut un appel à AddAccountClaimsPrincipalFactory qui ajoute une fabrique de principal de revendications de compte avec le CustomAccountFactory.

Si l’application utilise une classe de compte d’utilisateur personnalisée qui s’étend RemoteUserAccount, changez la classe de compte d’utilisateur personnalisée pour RemoteUserAccount dans le code suivant.

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

Vous pouvez utiliser le composant UserClaims suivant pour étudier les revendications de l’utilisateur après l’authentification de l’utilisateur avec 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;
    }
}

Ajoutez un lien vers la page du composant dans le composant 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>

Lorsque vous effectuez des tests en local avec le kit de développement logiciel (SDK) Graph, nous vous recommandons d’utiliser une nouvelle session de navigateur privée/incognito pour chaque test afin d’éviter que les cookies persistants n’interfèrent avec les tests. Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Les exemples suivants utilisent un HttpClient nommé pour les appels d’API Graph pour obtenir le numéro de téléphone mobile d’un utilisateur pour traiter un appel ou personnaliser les revendications d’un utilisateur afin d’inclure une revendication de numéro de téléphone mobile et une revendication d’emplacement de bureau.

Les exemples nécessitent une référence de package pour Microsoft.Extensions.Http pour l’application autonome Blazor WebAssembly.

Les exemples nécessitent une référence de package pour Microsoft.Extensions.Http pour l’application autonome Blazor WebAssembly ou l’application Client d’une solution hébergée Blazor WebAssembly.

Remarque

Pour obtenir des conseils sur l’ajout de packages à des applications .NET, consultez les articles figurant sous Installer et gérer des packages dans Flux de travail de la consommation des packages (documentation NuGet). Vérifiez les versions du package sur NuGet.org.

Dans le Portail Azure, accordez des permissions déléguées (étendues)† pour les données Microsoft Graph auxquelles l’application doit pouvoir accéder pour le compte d’un utilisateur. Pour l’exemple de cet article, l’inscription de l’application doit comprendre une autorisation déléguée de lire les données utilisateur (Microsoft.Graph>User.Read étendue dans les autorisations d’API, Type : Délégué). L’étendue User.Read permet aux utilisateurs à se connecter à l’application, mais également à l’application à lire le profil et les informations sur la société des utilisateurs connectés. Pour plus d’informations, consultez Vue d’ensemble des autorisations et du consentement dans la plateforme identity Microsoft et Vue d’ensemble des autorisations Microsoft Graph.

Permissions et étendues signifient la même chose et sont interchangeables dans la documentation de sécurité et dans le Portail Azure. Sauf si le texte fait référence au portail Azure, cet article utilise étendue/étendues pour désigner les autorisations Graph.

Les étendues ne respectent pas la casse, User.Read est donc la même chose que user.read. N’hésitez pas à utiliser l’un ou l’autre format, mais nous vous recommandons de faire preuve de cohérence dans le code de l’application.

Après avoir ajouté les étendues de l’API Microsoft Graph dans l’inscription de l’application dans le Portail Azure, ajoutez la configuration suivante des paramètres d’application au fichier wwwroot/appsettings.json. Ce dernier contient l’URL de base Graph avec la version et les étendues graph. Dans l’exemple suivant, l’étendue User.Read est spécifiée pour les exemples dans les sections ultérieures de cet article. Les étendues ne respectent pas la casse.

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

Dans l’exemple précédent, l’espace réservé {VERSION} est la version de l’API Microsoft Graph (par exemple : v1.0).

Voici un exemple de fichier de configuration wwwroot/appsettings.json complet pour une application qui utilise ME-ID comme fournisseur d’identity, dans lequel la lecture des données utilisateur (étendue user.read) est spécifiée pour 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"
    ]
  }
}

Dans l’exemple précédent, l’espace réservé {TENANT ID} est l’ID de l’annuaire (locataire), tandis que l’espace réservé {CLIENT ID} est l’ID de l’application (client). Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Créez la configuration de projet et de classe suivante GraphAuthorizationMessageHandler dans le fichier Program pour utiliser l’API Graph. L’URL de base et les étendues sont fournies au gestionnaire à partir de la configuration.

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" ]);
    }
}

La barre oblique de fin (/) de l’URL autorisée est requise. Le code précédent génère l’URL autorisée suivante à partir de la configuration des paramètres d’application ou correspond par défaut à l’URL autorisée suivante si la configuration des paramètres de l’application est manquante : https://graph.microsoft.com/v1.0/.

Dans le fichier Program, configurez le HttpClient nommé pour l’API Graph :

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

Dans l’exemple précédent, le GraphAuthorizationMessageHandlerDelegatingHandler est inscrit en tant que service temporaire pour AddHttpMessageHandler. L’inscription temporaire est recommandée pour IHttpClientFactory, qui gère ses propres étendues de DI. Pour plus d'informations, reportez-vous aux ressources suivantes :

Une barre oblique de fin (/) sur l’adresse de base est requise. Dans le code précédent, le troisième argument de string.Join est string.Empty pour s’assurer que la barre oblique de fin est présente : https://graph.microsoft.com/v1.0/.

Appeler l’API Graph à partir d’un composant à l’aide d’un HttpClient nommé

La classe UserInfo.cs désigne les propriétés de profil utilisateur requises avec l’attribut JsonPropertyNameAttribute et le nom JSON utilisé par ME-ID. L’exemple suivant configure les propriétés du numéro de téléphone mobile et de l’emplacement du bureau de l’utilisateur.

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

Dans le composant UserData suivant, un HttpClient est créé pour API Graph pour émettre une requête de données de profil de l’utilisateur. La ressource me (me) est ajoutée à l’URL de base avec la version de la requête d’API Graph. Les données JSON renvoyées par Graph sont désérialisées dans les propriétés de la classe UserInfo. Dans l’exemple suivant, le numéro de téléphone mobile est obtenu. Vous pouvez ajouter du code similaire pour inclure l’emplacement du bureau du profil ME-ID de l’utilisateur si vous le souhaitez (userInfo.OfficeLocation). Si la requête de jeton d’accès échoue, l’utilisateur est redirigé pour se connecter à l’application pour un nouveau jeton d’accès.

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

Ajoutez un lien vers la page du composant dans le composant 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>

Conseil

Pour ajouter des utilisateurs à une application, consultez la section Attribuer des utilisateurs à une inscription d’application, avec ou sans rôles d’application.

La séquence suivante décrit le nouveau flux utilisateur pour les étendues de l’API Graph :

  1. Le nouvel utilisateur se connecte à l’application pour la première fois.
  2. L’utilisateur consent à utiliser l’application dans l’interface utilisateur de consentement Azure.
  3. L’utilisateur accède à une page du composant qui requiert des données de l’API Graph pour la première fois.
  4. L’utilisateur est redirigé vers l’interface utilisateur de consentement Azure pour donner son consentement aux étendues de l’API Graph.
  5. Les données utilisateur de l’API Graph sont retournées.

Si vous préférez que l’approvisionnement de l’étendue (consentement pour les étendues de l’API Graph) survienne lors de la connexion initiale, fournissez des étendues à l’authentification MSAL en tant qu’étendues de jeton d’accès par défaut dans le fichier 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);
+   }
});

Important

Consultez la section DefaultAccessTokenScopes plutôt que AdditionalScopesToConsent pour obtenir une explication sur la raison pour laquelle le code précédent utilise DefaultAccessTokenScopes (plutôt que AdditionalScopesToConsent) pour ajouter les étendues.

Lorsque les modifications précédentes sont apportées à l’application, le flux utilisateur adopte la séquence suivante :

  1. Le nouvel utilisateur se connecte à l’application pour la première fois.
  2. L’utilisateur consent à utiliser l’application et les étendues de l’API Graph dans l’interface utilisateur de consentement Azure.
  3. L’utilisateur accède à une page du composant qui requiert des données de l’API Graph pour la première fois.
  4. Les données utilisateur de l’API Graph sont retournées.

Lorsque vous effectuez des tests avec l’API Graph en local, nous vous recommandons d’utiliser une nouvelle session de navigateur privée/incognito pour chaque test afin d’empêcher les cookies persistants d’interférer avec les tests. Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Personnaliser les revendications utilisateur à l’aide d’un HttpClient nommé

Dans l’exemple suivant, l’application crée un numéro de téléphone mobile et des revendications d’emplacement de bureau pour l’utilisateur à partir des données de son profil utilisateur ME-ID. L’application doit avoir l’étendue de l’API Graph User.Read configurée dans ME-ID. Les comptes d’utilisateur de test dans ME-ID nécessitent une entrée pour le numéro de téléphone mobile et l’emplacement du bureau, qui peuvent être ajoutés via le portail Azure à leurs profils utilisateur.

Si vous n’avez pas encore ajouté la classe UserInfo à l’application en suivant les instructions décrites plus haut dans cet article, ajoutez la classe suivante et désignez les propriétés de profil utilisateur requises avec l’attribut JsonPropertyNameAttribute et le nom JSON utilisé par ME-ID. L’exemple suivant configure les propriétés du numéro de téléphone mobile et de l’emplacement du bureau de l’utilisateur.

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

Dans la fabrique de compte d’utilisateur personnalisée suivante :

  • Un ILogger (logger) est inclus pour des raisons pratiques au cas où vous souhaitez consigner des informations ou des erreurs dans la méthode CreateUserAsync.
  • Si une exception AccessTokenNotAvailableException est renvoyée, l’utilisateur est redirigé vers le fournisseur d’identity pour se connecter à son compte. Des actions supplémentaires ou différentes peuvent être effectuées lors de l’échec de la requête d’un jeton d’accès. Par exemple, l’application peut enregistrer le AccessTokenNotAvailableException et créer un ticket de support pour une investigation plus approfondie.
  • Le framework RemoteUserAccount représente le compte de l’utilisateur. Si l’application nécessite une classe de compte d’utilisateur personnalisée qui étend RemoteUserAccount, changez la classe de compte d’utilisateur personnalisée pour RemoteUserAccount dans le code suivant.

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

L’authentification MSAL est configurée pour utiliser la fabrique de compte d’utilisateur personnalisée. Commencez par confirmer que le Program fichier utilise l’espace Microsoft.AspNetCore.Components.WebAssembly.Authentication de noms :

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Dans le fichier Program, recherchez l’appel à la méthode d’extension AddMsalAuthentication. Mettez à jour le code suivant, ce qui inclut un appel à AddAccountClaimsPrincipalFactory qui ajoute une fabrique de principal de revendications de compte avec le CustomAccountFactory.

Si l’application utilise une classe de compte d’utilisateur personnalisée qui étend RemoteUserAccount, changez la classe de compte d’utilisateur personnalisé de votre application pour RemoteUserAccount dans le code suivant.

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

L’exemple précédent concerne une application qui utilise l’authentification ME-ID avec MSAL. Des modèles similaires existent pour l’authentification OIDC et l’API. Pour plus d’informations, consultez les exemples de la section Personnaliser l’utilisateur avec une revendication de charge utile de l’article scénarios de sécurité supplémentaires d’ASP.NET CoreBlazor WebAssembly.

Vous pouvez utiliser le composant UserClaims suivant pour étudier les revendications de l’utilisateur après l’authentification de l’utilisateur avec 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;
    }
}

Ajoutez un lien vers la page du composant dans le composant 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>

Lorsque vous effectuez des tests avec l’API Graph en local, nous vous recommandons d’utiliser une nouvelle session de navigateur privée/incognito pour chaque test afin d’empêcher les cookies persistants d’interférer avec les tests. Pour plus d’informations, consultez Sécuriser une application autonome ASP.NET Core Blazor WebAssembly avec Microsoft Entra ID.

Attribuer des utilisateurs à une inscription d’application, avec ou sans rôles d’application

Vous pouvez ajouter des utilisateurs à une inscription d’application et attribuer des rôles aux utilisateurs, en procédant comme suit dans le Portail Azure.

Pour ajouter un utilisateur, sélectionnez Utilisateurs dans la zone ME-ID du Portail Azure :

  1. Sélectionnez Nouvel utilisateur>Créer un nouvel utilisateur.
  2. Utilisez le modèle Créer un utilisateur.
  3. Fournissez les informations de l’utilisateur dans la zone Identity.
  4. Vous pouvez générer un mot de passe initial ou attribuer un mot de passe initial que l’utilisateur modifie lorsqu’il se connecte pour la première fois. Si vous utilisez le mot de passe généré par le portail, prenez-en note maintenant.
  5. Sélectionnez Créer pour créer l’utilisateur. À la fermeture de l’interface Créer un utilisateur, sélectionnez Actualiser pour mettre à jour la liste des utilisateurs et afficher le nouvel utilisateur.
  6. Pour les exemples de cet article, attribuez un numéro de téléphone mobile au nouvel utilisateur en sélectionnant son nom dans la liste des utilisateurs, puis Propriétés et en modifiant les informations de contact pour fournir un numéro de téléphone mobile.

Pour assigner des utilisateurs à l’application sans rôles d’application :

  1. Dans la zone ME-ID du Portail Azure, ouvrez Applications d’entreprise.
  2. Créez l’application web à partir de la liste.
  3. Sélectionnez Utilisateurs et groupes.
  4. Sélectionner Ajouter un utilisateur/groupe.
  5. Sélectionnez un utilisateur.
  6. Cliquez sur le bouton Affecter.

Pour assigner des utilisateurs à l’application avec rôles d’application :

  1. Ajoutez des rôles à l’inscription de l’application dans le Portail Azure en suivant les instructions dans ASP.NET Core Blazor WebAssembly avec des groupes et des rôles Microsoft Entra ID.
  2. Dans la zone ME-ID du Portail Azure, ouvrez Applications d’entreprise.
  3. Créez l’application web à partir de la liste.
  4. Sélectionnez Utilisateurs et groupes.
  5. Sélectionner Ajouter un utilisateur/groupe.
  6. Sélectionnez un utilisateur, mais également son rôle pour accéder à l’application. Plusieurs rôles sont attribués à un utilisateur en répétant le processus d’ajout de l’utilisateur à l’application jusqu’à l’attribution de tous les rôles de l’utilisateur. Les utilisateurs disposant de plusieurs rôles sont répertoriés une fois pour chacun des rôles attribués dans la liste d’utilisateurs Utilisateurs et groupes de l’application.
  7. Cliquez sur le bouton Affecter.

DefaultAccessTokenScopes contre AdditionalScopesToConsent

Les exemples dans cet article approvisionnent des étendues de l’API Graph avec DefaultAccessTokenScopes (non AdditionalScopesToConsent).

AdditionalScopesToConsent n’est pas utilisé, car incapable d’approvisionner des étendues de l’API Graph pour des utilisateurs lors de leur connexion initiale avec MSAL à l’application par l’interface utilisateur de consentement Azure. Lorsque l’utilisateur tente d’accéder à l’API Graph pour la première fois avec le kit de développement logiciel (SDK) Graph, il est confronté à une exception :

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

Une fois qu’un utilisateur approvisionne des étendues de l’API Graph fournies par DefaultAccessTokenScopes, l’application peut utiliser AdditionalScopesToConsent pour une connexion utilisateur ultérieure. Toutefois, la modification du code de l’application n’a aucun sens pour une application de production nécessitant l’ajout périodique de nouveaux utilisateurs avec des étendues Graph déléguées ou l’ajout de nouvelles étendues de l’API Graph déléguées à l’application.

La discussion précédente sur l’approvisionnement des étendues pour l’accès à l’API Graph, lorsque l’utilisateur se connecte d’abord à l’application, s’applique uniquement à :

  • Applications qui adoptent le kit de développement logiciel (SDK) Graph.
  • Les applications qui utilisent un HttpClient nommé pour l’accès à l’API Graph. Cette dernière demande aux utilisateurs de donner leur consentement aux étendues Graph lors de leur connexion initiale à l’application.

Lorsque vous utilisez un HttpClient nommé ne demandant pas aux utilisateurs de donner leur consentement aux étendues Graph lors de leur première initiale, les utilisateurs sont redirigés vers l’interface utilisateur de consentement Azure pour les étendues de l’API Graph lorsqu’ils demandent au préalable un accès à l’API Graph par le DelegatingHandler du HttpClient préconfiguré et nommé. Lorsque des étendues Graph ne sont pas consenties initialement avec l’approche du HttpClient nommé, que ni DefaultAccessTokenScopes ou AdditionalScopesToConsent ne sont appelées par l’application. Pour plus d’informations, consultez la couverture du HttpClient nommé dans cet article.

Solutions Blazor WebAssemblyhébergées

Les exemples de cet article concernent l’utilisation du Kit de développement logiciel (SDK) Graph ou d’un HttpClient nommé avec l’API Graph directement à partir d’une application Blazor WebAssembly autonome ou directement à partir de l’application Client d’une solution Blazor WebAssemblyhébergée. Un autre scénario qui n’est pas abordé dans cet article est qu’une application Client d’une solution hébergée appelle l’application Server de la solution via l’API web, puis que l’application Server utilise le Kit de développement logiciel (SDK)/API Graph pour appeler Microsoft Graph et retourner des données à l’application Client. Bien qu’il s’agit d’une approche prise en charge, elle n’est pas couverte par cet article. Si vous souhaitez adopter cette approche :

  • Suivez les instructions de Appeler une API web à partir d’une application ASP.NET Blazor Core pour les aspects de l’API web lors de l’émission de demandes à l’application Server à partir de l’application Client et en retournant des données à l’application Client .
  • Suivez les instructions de la documentation principale de Microsoft Graph pour utiliser le Kit de développement logiciel (SDK) Graph avec une application standard ASP.NET Core, qui, dans ce scénario, est l’application Server de la solution. Si vous utilisez le modèle de projet Blazor WebAssembly pour créer la solution hébergée Blazor WebAssembly (ASP.NET Core Hosted/-h|--hosted) avec l’autorisation organisationnelle (organisation unique/SingleOrg ou organisations multiples/MultiOrg) et l’option Microsoft Graph (Plateforme d’identity Microsoft>Services connectés>Ajouter des autorisations Microsoft Graph dans Visual Studio ou l’option --calls-graph avec la commande CLI .NET dotnet new), l’application Server de la solution est configurée pour utiliser le kit de développement logiciel (SDK) Graph lorsque la solution est créée à partir du modèle de projet.

Ressources supplémentaires

Règle générale

  • Documentation Microsoft Graph
  • Exemple d’application Microsoft GraphBlazor WebAssembly : cet exemple montre comment utiliser le Kit de développement logiciel (SDK) Microsoft Graph .NET pour accéder aux données dans Office 365 à partir d’applications Blazor WebAssembly .
  • Créer des applications .NET avec le didacticiel Microsoft Graph et l’exemple d’applicationMicrosoft Graph ASP.NET Core : ces ressources sont les plus appropriées pour les solutions hébergéesBlazor WebAssembly , où l’application Server est configurée pour accéder à Microsoft Graph comme une application standard ASP.NET Core pour le compte de l’application. Client L’application utilise l’API Client web pour effectuer des requêtes à l’application pour les Server données Graph. Bien que ces ressources ne s’appliquent pas directement à l’appel de Graph à partir de applications côté clientBlazor WebAssembly, la configuration de l’application ME-ID et les pratiques de codage Microsoft Graph dans les ressources liées sont pertinentes pour les applications Blazor WebAssembly autonomes et doivent être consultées pour connaître les meilleures pratiques générales.

Conseils de sécurité