Usare l'API Graph con ASP.NET Core Blazor WebAssembly
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Questo articolo illustra come usare Microsoft Graph nelle Blazor WebAssembly app, che consente alle app di accedere alle risorse di Microsoft Cloud.
Sono trattati due approcci:
Graph SDK: Microsoft Graph SDK semplifica la creazione di app di alta qualità, efficienti e resilienti che accedono a Microsoft Graph. Selezionare il pulsante Graph SDK nella parte superiore di questo articolo per adottare questo approccio.
Denominato HttpClient con l'API Graph: un oggetto denominato
HttpClient
può inviare richieste API Microsoft Graph direttamente a Microsoft Graph. Selezionare il pulsante Named HttpClient with Graph API (HttpClient denominato con API Graph) nella parte superiore di questo articolo per adottare questo approccio.
Le linee guida contenute in questo articolo non sono progettate per sostituire la documentazione di Microsoft Graph e le linee guida sulla sicurezza di Azure in altri set di documentazione Microsoft. Valutare le indicazioni sulla sicurezza nella sezione Risorse aggiuntive di questo articolo prima di implementare Microsoft Graph in un ambiente di produzione. Seguire le procedure consigliate di Microsoft per limitare le vulnerabilità delle app.
Altri approcci per l'uso di Microsoft Graph e Blazor WebAssembly sono disponibili negli esempi di Microsoft Graph e Azure seguenti:
- App di esempio Blazor WebAssembly di Microsoft Graph: l'esempio adotta un approccio basato su factory con Microsoft Graph SDK per ottenere i dati di Office 365. L'esempio usa un valore predefinito HttpClient per effettuare richieste client Graph. Se è necessario usare l'impostazione predefinita HttpClient con l'indirizzo di base dell'app (
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
) per altri scopi, ad esempio per caricare i dati dalla radice Web dell'app, è consigliabile effettuare il refactoring della factory client Graph per usare un denominatoHttpClient
dedicato alle richieste Graph. - ASP.NET Core 8.0 Blazor WebAssembly | App autonoma | Accesso utente, accesso all'API Web protetta (Microsoft Graph) | Piattaforma Microsoftidentity: l'esempio è un'applicazione Web progressiva (PWA) che usa un gestore di messaggi di autorizzazione e HttpClient per ottenere i dati graph. Come per l'esempio precedente, questo esempio usa anche un valore predefinito HttpClient per effettuare richieste client Graph. Anziché usare Microsoft Graph SDK, l'esempio recupera i dati dell'account utente come JSON tramite una richiesta api Microsoft Graph in un componente. Si tratta di una tecnica simile all'approccio denominato HttpClient con l'API Graph in questo articolo (usare il pulsante nella parte superiore di questo articolo per visualizzare le indicazioni), ad eccezione del fatto che le linee guida di questo articolo usano un nome
HttpClient
dedicato alle richieste graph.
Per fornire commenti e suggerimenti su uno dei due esempi precedenti, aprire un problema nel repository GitHub dell'esempio. Se si sta aprendo un problema per l'esempio di Azure, fornire un collegamento all'esempio nel commento di apertura perché il repository di esempio di Azure (Azure-Samples
) contiene molti esempi. Descrivere il problema in dettaglio e includere il codice di esempio in base alle esigenze. Inserire un'app minima in GitHub che riproduce il problema o l'errore. Assicurarsi di rimuovere i dati di configurazione dell'account di Azure dall'esempio prima di eseguirne il commit nel repository pubblico.
Per fornire commenti e suggerimenti o richiedere assistenza per questo articolo o ASP.NET Core, vedere nozioni fondamentali su ASP.NET CoreBlazor.
Importante
Gli scenari descritti in questo articolo si applicano all'uso di Microsoft Entra (ME-ID) come identity provider, non AAD B2C. L'uso di Microsoft Graph con un'app lato Blazor WebAssembly client e il provider AAD B2C identity non è attualmente supportato perché l'app richiederebbe un segreto client, che non può essere protetto nell'app lato Blazor client. Per un'app autonoma Blazor WebAssembly AAD B2C usare l'API Graph, creare un'API del server back-end (Web) per accedere all'API Graph per conto degli utenti. L'app sul lato client autentica e autorizza gli utenti a chiamare l'API Web per accedere in modo sicuro a Microsoft Graph e restituire i dati all'app lato Blazor client dall'API Web basata su server. Il segreto client viene mantenuto in modo sicuro nell'API Web basata su server, non nell'app Blazor nel client. Non archiviare mai un segreto client in un'app lato Blazor client.
L'uso di un'app ospitata Blazor WebAssembly è supportato, in cui l'app Server usa Graph SDK/API per fornire dati Graph all'app Client tramite l'API Web. Per altre informazioni, vedere la sezione Soluzioni ospitate Blazor WebAssembly di questo articolo.
Gli esempi in questo articolo sfruttano le nuove funzionalità di .NET/C#. Quando si usano gli esempi con .NET 7 o versioni precedenti, sono necessarie modifiche secondarie. Tuttavia, gli esempi di testo e codice relativi all'interazione con Microsoft Graph sono gli stessi per tutte le versioni di ASP.NET Core.
Le indicazioni seguenti si applicano a Microsoft Graph v5.
Microsoft Graph SDK per l'uso nelle Blazor app è denominato libreria client .NET di Microsoft Graph.
Gli esempi di Graph SDK richiedono i riferimenti al pacchetto seguenti nell'app autonoma Blazor WebAssembly . I primi due pacchetti sono già a cui viene fatto riferimento se l'app è stata abilitata per l'autenticazione MSAL, ad esempio quando si crea l'app seguendo le indicazioni riportate in Proteggere un'app autonoma ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Gli esempi di Graph SDK richiedono i riferimenti al pacchetto seguenti nell'app autonoma Blazor WebAssembly o nell'app Client di una soluzione ospitata Blazor WebAssembly . I primi due pacchetti sono già a cui viene fatto riferimento se l'app è stata abilitata per l'autenticazione MSAL, ad esempio quando si crea l'app seguendo le indicazioni riportate in Proteggere un'app autonoma ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Microsoft.AspNetCore.Components.WebAssembly.Authentication
Microsoft.Authentication.WebAssembly.Msal
Microsoft.Extensions.Http
Microsoft.Graph
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Nella portale di Azure concedere autorizzazioni delegate (ambiti)† per i dati di Microsoft Graph a cui l'app deve poter accedere per conto di un utente. Per l'esempio in questo articolo, la registrazione dell'app deve includere l'autorizzazione delegata per leggere i dati utente (Microsoft.Graph
>User.Read
ambito nelle autorizzazioni API, Tipo: Delegato). L'ambito User.Read
consente agli utenti di accedere all'app e consente all'app di leggere il profilo e le informazioni aziendali degli utenti connessi. Per altre informazioni, vedere Panoramica delle autorizzazioni e del consenso nella piattaforma Microsoft identity e Panoramica delle autorizzazioni di Microsoft Graph.
†Permissions e ambiti indicano la stessa cosa e vengono usati in modo intercambiabile nella documentazione di sicurezza e nella portale di Azure. A meno che il testo non faccia riferimento alla portale di Azure, questo articolo usa ambiti di ambito/ quando si fa riferimento alle autorizzazioni graph.
Gli ambiti non fanno distinzione tra maiuscole e minuscole, quindi User.Read
equivale a user.read
. È possibile usare entrambi i formati, ma è consigliabile scegliere in modo coerente il codice dell'applicazione.
Dopo aver aggiunto gli ambiti dell'API Microsoft Graph alla registrazione dell'app nella portale di Azure, aggiungere la configurazione delle impostazioni dell'app seguente al wwwroot/appsettings.json
file nell'app, che include l'URL di base graph con la versione e gli ambiti di Microsoft Graph. Nell'esempio seguente viene specificato l'ambito User.Read
per gli esempi nelle sezioni successive di questo articolo. Gli ambiti non fanno distinzione tra maiuscole e minuscole.
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "{VERSION}",
"Scopes": [
"user.read"
]
}
Nell'esempio precedente il {VERSION}
segnaposto è la versione dell'API Microsoft Graph (ad esempio: v1.0
).
Di seguito è riportato un esempio di file di configurazione completo wwwroot/appsettings.json
per un'app che usa ME-ID come identity provider, in cui viene specificata la lettura dei dati utente (user.read
ambito) per 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"
]
}
}
Nell'esempio precedente il {TENANT ID}
segnaposto è l'ID directory (tenant) e il {CLIENT ID}
segnaposto è l'ID applicazione (client). Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Aggiungere la classe seguente GraphClientExtensions
all'app autonoma. Gli ambiti vengono forniti alla Scopes proprietà di AccessTokenRequestOptions nel AuthenticateRequestAsync
metodo .
Aggiungere la classe seguente GraphClientExtensions
all'app autonoma o Client all'app di una soluzione ospitataBlazor WebAssembly. Gli ambiti vengono forniti alla Scopes proprietà di AccessTokenRequestOptions nel AuthenticateRequestAsync
metodo .
Quando non viene ottenuto un token di accesso, il codice seguente non imposta un'intestazione di autorizzazione Bearer per le richieste 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}");
}
}
}
}
Importante
Per una spiegazione sul motivo per cui il codice precedente usa DefaultAccessTokenScopes per aggiungere gli ambiti anziché AdditionalScopesToConsent.DefaultAccessTokenScopes
AdditionalScopesToConsent
Program
Nel file aggiungere i servizi client Graph e la configurazione con il AddGraphClient
metodo di estensione. Per impostazione predefinita, il codice seguente è l'indirizzo di base e User.Read
gli ambiti di Microsoft Graph versione 1.0 se queste impostazioni non vengono trovate nel file delle impostazioni dell'app:
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);
Chiamare l'API Graph da un componente usando Graph SDK
Il componente seguente UserData
usa un oggetto inserito GraphServiceClient
per ottenere i dati del profilo ME-ID dell'utente e visualizzare il numero di telefono cellulare.
Per qualsiasi utente di test creato in ME-ID, assicurarsi di assegnare al profilo ME-ID dell'utente un numero di telefono cellulare nel portale di 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();
}
}
Aggiungere un collegamento alla pagina del componente nel NavMenu
componente (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>
Suggerimento
Per aggiungere utenti a un'app, vedere la sezione Assegnare utenti a una registrazione dell'app con o senza ruoli dell'app.
Quando si esegue il test con Graph SDK in locale, è consigliabile usare una nuova sessione del browser InPrivate/incognito per ogni test per impedire che i cookie persistenti interferiscano con i test. Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Personalizzare le attestazioni utente con Graph SDK
Nell'esempio seguente l'app crea le attestazioni relative al numero di telefono cellulare e alla posizione dell'ufficio per un utente dai dati del profilo utente ME-ID. L'app deve avere l'ambito dell'API User.Read
Graph configurato in ME-ID. Tutti gli utenti di test per questo scenario devono avere un numero di telefono cellulare e la posizione dell'ufficio nel profilo ME-ID, che può essere aggiunto tramite il portale di Azure.
Nella factory dell'account utente personalizzata seguente:
- Un ILogger oggetto (
logger
) è incluso per praticità nel caso in cui si desideri registrare informazioni o errori nelCreateUserAsync
metodo . - Nel caso in cui venga generata un'eccezione AccessTokenNotAvailableException , l'utente viene reindirizzato al identity provider per accedere al proprio account. È possibile eseguire azioni aggiuntive o diverse quando la richiesta di un token di accesso non riesce. Ad esempio, l'app può registrare AccessTokenNotAvailableException e creare un ticket di supporto per ulteriori indagini.
- Il framework rappresenta l'account RemoteUserAccount dell'utente. Se l'app richiede una classe di account utente personalizzata che estende RemoteUserAccount, scambiare la classe di account utente personalizzata per RemoteUserAccount nel codice seguente.
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;
}
}
Configurare l'autenticazione MSAL per l'uso della factory dell'account utente personalizzata.
Verificare che il Program
file usi lo Microsoft.AspNetCore.Components.WebAssembly.Authentication spazio dei nomi :
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
L'esempio in questa sezione si basa sull'approccio di lettura dell'URL di base con la versione e gli ambiti dalla configurazione dell'app tramite la MicrosoftGraph
sezione nel wwwroot/appsettings.json
file. Le righe seguenti dovrebbero essere già presenti nel Program
file seguendo le indicazioni riportate in precedenza in questo articolo:
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);
Program
Nel file trovare la chiamata al AddMsalAuthentication metodo di estensione. Aggiornare il codice al codice seguente, che include una chiamata a AddAccountClaimsPrincipalFactory che aggiunge una factory dell'entità attestazioni dell'account con .CustomAccountFactory
Se l'app usa una classe di account utente personalizzata che estende RemoteUserAccount, scambiare la classe di account utente personalizzata per RemoteUserAccount nel codice seguente.
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
RemoteUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
CustomAccountFactory>();
È possibile usare il componente seguente UserClaims
per studiare le attestazioni dell'utente dopo l'autenticazione dell'utente con 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;
}
}
Aggiungere un collegamento alla pagina del componente nel NavMenu
componente (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>
Quando si esegue il test con Graph SDK in locale, è consigliabile usare una nuova sessione del browser InPrivate/incognito per ogni test per impedire che i cookie persistenti interferiscano con i test. Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Le indicazioni seguenti si applicano a Microsoft Graph v4. Se si sta aggiornando un'app dall'SDK v4 alla versione 5, vedere la guida al log delle modifiche e all'aggiornamento di Microsoft Graph .NET SDK v5.
Microsoft Graph SDK per l'uso nelle Blazor app è denominato libreria client .NET di Microsoft Graph.
Gli esempi di Graph SDK richiedono i riferimenti al pacchetto seguenti nell'app autonoma Blazor WebAssembly . I primi due pacchetti sono già a cui viene fatto riferimento se l'app è stata abilitata per l'autenticazione MSAL, ad esempio quando si crea l'app seguendo le indicazioni riportate in Proteggere un'app autonoma ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Gli esempi di Graph SDK richiedono i riferimenti al pacchetto seguenti nell'app autonoma Blazor WebAssembly o nell'app Client di una soluzione ospitata Blazor WebAssembly . I primi due pacchetti sono già a cui viene fatto riferimento se l'app è stata abilitata per l'autenticazione MSAL, ad esempio quando si crea l'app seguendo le indicazioni riportate in Proteggere un'app autonoma ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Microsoft.AspNetCore.Components.WebAssembly.Authentication
Microsoft.Authentication.WebAssembly.Msal
Microsoft.Extensions.Http
Microsoft.Graph
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Nella portale di Azure concedere autorizzazioni delegate (ambiti)† per i dati di Microsoft Graph a cui l'app deve poter accedere per conto di un utente. Per l'esempio in questo articolo, la registrazione dell'app deve includere l'autorizzazione delegata per leggere i dati utente (Microsoft.Graph
>User.Read
ambito nelle autorizzazioni API, Tipo: Delegato). L'ambito User.Read
consente agli utenti di accedere all'app e consente all'app di leggere il profilo e le informazioni aziendali degli utenti connessi. Per altre informazioni, vedere Panoramica delle autorizzazioni e del consenso nella piattaforma Microsoft identity e Panoramica delle autorizzazioni di Microsoft Graph.
†Permissions e ambiti indicano la stessa cosa e vengono usati in modo intercambiabile nella documentazione di sicurezza e nella portale di Azure. A meno che il testo non faccia riferimento alla portale di Azure, questo articolo usa ambiti di ambito/ quando si fa riferimento alle autorizzazioni graph.
Gli ambiti non fanno distinzione tra maiuscole e minuscole, quindi User.Read
equivale a user.read
. È possibile usare entrambi i formati, ma è consigliabile scegliere in modo coerente il codice dell'applicazione.
Dopo aver aggiunto gli ambiti dell'API Microsoft Graph alla registrazione dell'app nella portale di Azure, aggiungere la configurazione delle impostazioni dell'app seguente al wwwroot/appsettings.json
file nell'app, che include l'URL di base graph con la versione e gli ambiti di Microsoft Graph. Nell'esempio seguente viene specificato l'ambito User.Read
per gli esempi nelle sezioni successive di questo articolo. Gli ambiti non fanno distinzione tra maiuscole e minuscole.
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "{VERSION}",
"Scopes": [
"user.read"
]
}
Nell'esempio precedente il {VERSION}
segnaposto è la versione dell'API Microsoft Graph (ad esempio: v1.0
).
Di seguito è riportato un esempio di file di configurazione completo wwwroot/appsettings.json
per un'app che usa ME-ID come identity provider, in cui viene specificata la lettura dei dati utente (user.read
ambito) per 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"
]
}
}
Nell'esempio precedente il {TENANT ID}
segnaposto è l'ID directory (tenant) e il {CLIENT ID}
segnaposto è l'ID applicazione (client). Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Aggiungere la classe seguente GraphClientExtensions
all'app autonoma. Gli ambiti vengono forniti alla Scopes proprietà di AccessTokenRequestOptions nel AuthenticateRequestAsync
metodo . Viene IHttpProvider.OverallTimeout esteso dal valore predefinito da 100 secondi a 300 secondi per dare più HttpClient tempo per ricevere una risposta da Microsoft Graph.
Aggiungere la classe seguente GraphClientExtensions
all'app autonoma o Client all'app di una soluzione ospitataBlazor WebAssembly. Gli ambiti vengono forniti alla Scopes proprietà di AccessTokenRequestOptions nel AuthenticateRequestAsync
metodo . Viene IHttpProvider.OverallTimeout esteso dal valore predefinito da 100 secondi a 300 secondi per dare più HttpClient tempo per ricevere una risposta da Microsoft Graph.
Quando non viene ottenuto un token di accesso, il codice seguente non imposta un'intestazione di autorizzazione Bearer per le richieste 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()
{
}
}
}
Importante
Per una spiegazione sul motivo per cui il codice precedente usa DefaultAccessTokenScopes per aggiungere gli ambiti anziché AdditionalScopesToConsent.DefaultAccessTokenScopes
AdditionalScopesToConsent
Program
Nel file aggiungere i servizi client Graph e la configurazione con il metodo di AddGraphClient
estensione:
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);
Chiamare l'API Graph da un componente usando Graph SDK
Il componente seguente UserData
usa un oggetto inserito GraphServiceClient
per ottenere i dati del profilo ME-ID dell'utente e visualizzare il numero di telefono cellulare. Per qualsiasi utente di test creato in ME-ID, assicurarsi di assegnare al profilo ME-ID dell'utente un numero di telefono cellulare nel portale di 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();
}
}
Aggiungere un collegamento alla pagina del componente nel NavMenu
componente (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>
Suggerimento
Per aggiungere utenti a un'app, vedere la sezione Assegnare utenti a una registrazione dell'app con o senza ruoli dell'app.
Quando si esegue il test con Graph SDK in locale, è consigliabile usare una nuova sessione del browser InPrivate/incognito per ogni test per impedire che i cookie persistenti interferiscano con i test. Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Personalizzare le attestazioni utente con Graph SDK
Nell'esempio seguente l'app crea le attestazioni relative al numero di telefono cellulare e alla posizione dell'ufficio per un utente dai dati del profilo utente ME-ID. L'app deve avere l'ambito dell'API User.Read
Graph configurato in ME-ID. Tutti gli utenti di test per questo scenario devono avere un numero di telefono cellulare e la posizione dell'ufficio nel profilo ME-ID, che può essere aggiunto tramite il portale di Azure.
Nella factory dell'account utente personalizzata seguente:
- Un ILogger oggetto (
logger
) è incluso per praticità nel caso in cui si desideri registrare informazioni o errori nelCreateUserAsync
metodo . - Nel caso in cui venga generata un'eccezione AccessTokenNotAvailableException , l'utente viene reindirizzato al identity provider per accedere al proprio account. È possibile eseguire azioni aggiuntive o diverse quando la richiesta di un token di accesso non riesce. Ad esempio, l'app può registrare AccessTokenNotAvailableException e creare un ticket di supporto per ulteriori indagini.
- Il framework rappresenta l'account RemoteUserAccount dell'utente. Se l'app richiede una classe di account utente personalizzata che estende RemoteUserAccount, scambiare la classe di account utente personalizzata per RemoteUserAccount nel codice seguente.
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;
}
}
Configurare l'autenticazione MSAL per l'uso della factory dell'account utente personalizzata.
Verificare che il Program
file usi lo Microsoft.AspNetCore.Components.WebAssembly.Authentication spazio dei nomi :
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
L'esempio in questa sezione si basa sull'approccio di lettura dell'URL di base con la versione e gli ambiti dalla configurazione dell'app tramite la MicrosoftGraph
sezione nel wwwroot/appsettings.json
file. Le righe seguenti dovrebbero essere già presenti nel Program
file seguendo le indicazioni riportate in precedenza in questo articolo:
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);
Program
Nel file trovare la chiamata al AddMsalAuthentication metodo di estensione. Aggiornare il codice al codice seguente, che include una chiamata a AddAccountClaimsPrincipalFactory che aggiunge una factory dell'entità attestazioni dell'account con .CustomAccountFactory
Se l'app usa una classe di account utente personalizzata che estende RemoteUserAccount, scambiare la classe di account utente personalizzata per RemoteUserAccount nel codice seguente.
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
RemoteUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
CustomAccountFactory>();
È possibile usare il componente seguente UserClaims
per studiare le attestazioni dell'utente dopo l'autenticazione dell'utente con 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;
}
}
Aggiungere un collegamento alla pagina del componente nel NavMenu
componente (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>
Quando si esegue il test con Graph SDK in locale, è consigliabile usare una nuova sessione del browser InPrivate/incognito per ogni test per impedire che i cookie persistenti interferiscano con i test. Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Gli esempi seguenti usano un denominato HttpClient per le chiamate API Graph per ottenere il numero di telefono cellulare di un utente per elaborare una chiamata o per personalizzare le attestazioni di un utente in modo da includere un'attestazione di numero di telefono cellulare e un'attestazione di posizione dell'ufficio.
Gli esempi richiedono un riferimento al pacchetto per Microsoft.Extensions.Http
l'app autonoma Blazor WebAssembly .
Gli esempi richiedono un riferimento al pacchetto per Microsoft.Extensions.Http
l'app autonoma Blazor WebAssembly o l'app Client di una soluzione ospitata Blazor WebAssembly .
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Nella portale di Azure concedere autorizzazioni delegate (ambiti)† per i dati di Microsoft Graph a cui l'app deve poter accedere per conto di un utente. Per l'esempio in questo articolo, la registrazione dell'app deve includere l'autorizzazione delegata per leggere i dati utente (Microsoft.Graph
>User.Read
ambito nelle autorizzazioni API, Tipo: Delegato). L'ambito User.Read
consente agli utenti di accedere all'app e consente all'app di leggere il profilo e le informazioni aziendali degli utenti connessi. Per altre informazioni, vedere Panoramica delle autorizzazioni e del consenso nella piattaforma Microsoft identity e Panoramica delle autorizzazioni di Microsoft Graph.
†Permissions e ambiti indicano la stessa cosa e vengono usati in modo intercambiabile nella documentazione di sicurezza e nella portale di Azure. A meno che il testo non faccia riferimento alla portale di Azure, questo articolo usa ambiti di ambito/ quando si fa riferimento alle autorizzazioni graph.
Gli ambiti non fanno distinzione tra maiuscole e minuscole, quindi User.Read
equivale a user.read
. È possibile usare entrambi i formati, ma è consigliabile scegliere in modo coerente il codice dell'applicazione.
Dopo aver aggiunto gli ambiti dell'API Microsoft Graph alla registrazione dell'app nella portale di Azure, aggiungere la configurazione delle impostazioni dell'app seguente al wwwroot/appsettings.json
file nell'app, che include l'URL di base graph con la versione e gli ambiti di Microsoft Graph. Nell'esempio seguente viene specificato l'ambito User.Read
per gli esempi nelle sezioni successive di questo articolo. Gli ambiti non fanno distinzione tra maiuscole e minuscole.
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "{VERSION}",
"Scopes": [
"user.read"
]
}
Nell'esempio precedente il {VERSION}
segnaposto è la versione dell'API Microsoft Graph (ad esempio: v1.0
).
Di seguito è riportato un esempio di file di configurazione completo wwwroot/appsettings.json
per un'app che usa ME-ID come identity provider, in cui viene specificata la lettura dei dati utente (user.read
ambito) per 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"
]
}
}
Nell'esempio precedente il {TENANT ID}
segnaposto è l'ID directory (tenant) e il {CLIENT ID}
segnaposto è l'ID applicazione (client). Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Creare la classe e la configurazione del progetto seguenti GraphAuthorizationMessageHandler
nel file per l'uso Program
dell'API Graph. L'URL di base e gli ambiti vengono forniti al gestore dalla configurazione.
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" ]);
}
}
È necessaria la barra finale (/
) dell'URL autorizzato. Il codice precedente compila l'URL autorizzato seguente dalla configurazione delle impostazioni dell'app o usa l'URL autorizzato seguente se la configurazione delle impostazioni dell'app è mancante: https://graph.microsoft.com/v1.0/
.
Program
Nel file configurare l'API Graph denominataHttpClient:
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>();
Nell'esempio precedente l'oggetto GraphAuthorizationMessageHandler
DelegatingHandler viene registrato come servizio temporaneo per AddHttpMessageHandler. La registrazione temporanea è consigliata per IHttpClientFactory, che gestisce i propri ambiti di inserimento delle dipendenze. Per ulteriori informazioni, vedi le seguenti risorse:
- Classi di componenti di base dell'utilità per gestire un ambito di inserimento delle dipendenze
- Rilevare gli eliminabili temporanei sul lato client
È necessaria una barra finale (/
) sull'indirizzo di base. Nel codice precedente, il terzo argomento di string.Join
consiste string.Empty
nel garantire che la barra finale sia presente: https://graph.microsoft.com/v1.0/
.
Chiamare l'API Graph da un componente usando un denominato HttpClient
La UserInfo.cs
classe designa le proprietà del profilo utente necessarie con l'attributo JsonPropertyNameAttribute e il nome JSON usato da ME-ID. Nell'esempio seguente vengono impostate le proprietà per il numero di telefono cellulare e la posizione dell'ufficio dell'utente.
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; }
}
Nel componente seguente UserData
viene creato un oggetto HttpClient per l'API Graph per emettere una richiesta per i dati del profilo dell'utente. La me
risorsa (me
) viene aggiunta all'URL di base con la versione per la richiesta dell'API Graph. I dati JSON restituiti da Graph vengono deserializzati nelle proprietà della UserInfo
classe. Nell'esempio seguente viene ottenuto il numero di telefono cellulare. È possibile aggiungere codice simile per includere la posizione dell'ufficio del profilo ME-ID dell'utente, se lo si desidera (userInfo.OfficeLocation
). Se la richiesta di token di accesso non riesce, l'utente viene reindirizzato per accedere all'app per un nuovo token di accesso.
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();
}
}
}
Aggiungere un collegamento alla pagina del componente nel NavMenu
componente (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>
Suggerimento
Per aggiungere utenti a un'app, vedere la sezione Assegnare utenti a una registrazione dell'app con o senza ruoli dell'app.
La sequenza seguente descrive il nuovo flusso utente per gli ambiti dell'API Graph:
- Il nuovo utente accede all'app per la prima volta.
- L'utente acconsente all'uso dell'app nell'interfaccia utente del consenso di Azure.
- L'utente accede a una pagina del componente che richiede i dati dell'API Graph per la prima volta.
- L'utente viene reindirizzato all'interfaccia utente di consenso di Azure per fornire il consenso agli ambiti dell'API Graph.
- Vengono restituiti i dati utente dell'API Graph.
Se si preferisce che il provisioning dell'ambito (consenso per gli ambiti dell'API Graph) venga eseguito nell'accesso iniziale, fornire gli ambiti all'autenticazione MSAL come ambiti predefiniti del token di accesso nel Program
file:
+ 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);
+ }
});
Importante
Per una spiegazione sul motivo per cui il codice precedente usa DefaultAccessTokenScopes per aggiungere gli ambiti anziché AdditionalScopesToConsent.DefaultAccessTokenScopes
AdditionalScopesToConsent
Quando vengono apportate le modifiche precedenti all'app, il flusso utente adotta la sequenza seguente:
- Il nuovo utente accede all'app per la prima volta.
- L'utente acconsente all'uso dell'app e degli ambiti dell'API Graph nell'interfaccia utente del consenso di Azure.
- L'utente accede a una pagina del componente che richiede i dati dell'API Graph per la prima volta.
- Vengono restituiti i dati utente dell'API Graph.
Quando si esegue il test con l'API Graph in locale, è consigliabile usare una nuova sessione del browser InPrivate/incognito per ogni test per impedire che i cookie persistenti interferiscano con i test. Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Personalizzare le attestazioni utente usando un nome HttpClient
Nell'esempio seguente l'app crea le attestazioni relative al numero di telefono cellulare e alla posizione dell'ufficio per l'utente dai dati del profilo utente ME-ID. L'app deve avere l'ambito dell'API User.Read
Graph configurato in ME-ID. Gli account utente di test in ME-ID richiedono una voce per il numero di telefono cellulare e la posizione dell'ufficio, che possono essere aggiunti tramite il portale di Azure ai propri profili utente.
Se non è già stata aggiunta la UserInfo
classe all'app seguendo le indicazioni riportate in precedenza in questo articolo, aggiungere la classe seguente e designare le proprietà del profilo utente necessarie con l'attributo JsonPropertyNameAttribute e il nome JSON usato da ME-ID. Nell'esempio seguente vengono impostate le proprietà per il numero di telefono cellulare e la posizione dell'ufficio dell'utente.
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; }
}
Nella factory dell'account utente personalizzata seguente:
- Un ILogger oggetto (
logger
) è incluso per praticità nel caso in cui si desideri registrare informazioni o errori nelCreateUserAsync
metodo . - Nel caso in cui venga generata un'eccezione AccessTokenNotAvailableException , l'utente viene reindirizzato al identity provider per accedere al proprio account. È possibile eseguire azioni aggiuntive o diverse quando la richiesta di un token di accesso non riesce. Ad esempio, l'app può registrare AccessTokenNotAvailableException e creare un ticket di supporto per ulteriori indagini.
- Il framework rappresenta l'account RemoteUserAccount dell'utente. Se l'app richiede una classe di account utente personalizzata che estende RemoteUserAccount, scambiare la classe di account utente personalizzata per RemoteUserAccount nel codice seguente.
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'autenticazione MSAL è configurata per l'uso della factory dell'account utente personalizzata. Per iniziare, verificare che il Program
file usi lo Microsoft.AspNetCore.Components.WebAssembly.Authentication spazio dei nomi :
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
Program
Nel file trovare la chiamata al AddMsalAuthentication metodo di estensione. Aggiornare il codice al codice seguente, che include una chiamata a AddAccountClaimsPrincipalFactory che aggiunge una factory dell'entità attestazioni dell'account con .CustomAccountFactory
Se l'app usa una classe di account utente personalizzata che estende RemoteUserAccount, scambiare la classe di account utente personalizzata dell'app per RemoteUserAccount nel codice seguente.
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
RemoteUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount,
CustomAccountFactory>();
L'esempio precedente è relativo a un'app che usa l'autenticazione ME-ID con MSAL. Esistono modelli simili per l'autenticazione OIDC e API. Per altre informazioni, vedere gli esempi nella sezione Personalizzare l'utente con un'attestazione di payload dell'articolo scenari di sicurezza aggiuntivi di ASP.NET CoreBlazor WebAssembly.
È possibile usare il componente seguente UserClaims
per studiare le attestazioni dell'utente dopo l'autenticazione dell'utente con 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;
}
}
Aggiungere un collegamento alla pagina del componente nel NavMenu
componente (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>
Quando si esegue il test con l'API Graph in locale, è consigliabile usare una nuova sessione del browser InPrivate/incognito per ogni test per impedire che i cookie persistenti interferiscano con i test. Per altre informazioni, vedere Proteggere un'app autonoma di ASP.NET Core Blazor WebAssembly con Microsoft Entra ID.
Assegnare utenti a una registrazione dell'app con o senza ruoli dell'app
È possibile aggiungere utenti a una registrazione dell'app e assegnare ruoli agli utenti seguendo questa procedura nella portale di Azure.
Per aggiungere un utente, selezionare Utenti nell'area ME-ID del portale di Azure:
- Selezionare Nuovo utente>Crea nuovo utente.
- Usare il modello Crea utente .
- Fornire le informazioni dell'utente nell'area Identity .
- È possibile generare una password iniziale o assegnare una password iniziale modificata dall'utente al primo accesso. Se si usa la password generata dal portale, prendere nota di questa password.
- Selezionare Crea per creare l'utente. Quando crea nuova interfaccia utente si chiude, selezionare Aggiorna per aggiornare l'elenco utenti e visualizzare il nuovo utente.
- Per gli esempi in questo articolo, assegnare un numero di telefono cellulare al nuovo utente selezionando il nome dall'elenco degli utenti, selezionando Proprietà e modificando le informazioni di contatto per fornire un numero di telefono cellulare.
Per assegnare utenti all'app senza ruoli dell'app:
- Nell'area ME-ID del portale di Azure aprire Applicazioni aziendali.
- Selezionare l'app dall'elenco.
- Seleziona Utenti e gruppi.
- Selezionare Aggiungi utente/gruppo.
- Seleziona un utente.
- Selezionare il pulsante Assegna.
Per assegnare utenti all'app con ruoli dell'app:
- Aggiungere ruoli alla registrazione dell'app nel portale di Azure seguendo le indicazioni riportate in ASP.NET Core Blazor WebAssembly con i gruppi e i ruoli di Microsoft Entra ID.
- Nell'area ME-ID del portale di Azure aprire Applicazioni aziendali.
- Selezionare l'app dall'elenco.
- Seleziona Utenti e gruppi.
- Selezionare Aggiungi utente/gruppo.
- Selezionare un utente e selezionare il proprio ruolo per l'accesso all'app. Più ruoli vengono assegnati a un utente ripetendo il processo di aggiunta dell'utente all'app fino a quando non vengono assegnati tutti i ruoli per un utente. Gli utenti con più ruoli vengono elencati una volta per ogni ruolo assegnato nell'elenco Utenti e gruppi di utenti per l'app.
- Selezionare il pulsante Assegna.
DefaultAccessTokenScopes
e AdditionalScopesToConsent
Gli esempi in questo articolo effettuano il provisioning degli ambiti dell'API Graph con DefaultAccessTokenScopes, non AdditionalScopesToConsent.
AdditionalScopesToConsent non viene usato perché non è in grado di effettuare il provisioning degli ambiti dell'API Graph per gli utenti quando accedono all'app per la prima volta con MSAL tramite l'interfaccia utente del consenso di Azure. Quando l'utente tenta di accedere all'API Graph per la prima volta con Graph SDK, viene confrontato con un'eccezione:
Microsoft.Graph.Models.ODataErrors.ODataError: Access token is empty.
Dopo che un utente effettua il provisioning degli ambiti dell'API Graph forniti tramite DefaultAccessTokenScopes, l'app può usare AdditionalScopesToConsent per un accesso utente successivo. Tuttavia, la modifica del codice dell'app non ha senso per un'app di produzione che richiede l'aggiunta periodica di nuovi utenti con ambiti Graph delegati o l'aggiunta di nuovi ambiti dell'API Graph delegata all'app.
La discussione precedente su come effettuare il provisioning degli ambiti per l'accesso all'API Graph quando l'utente accede per la prima volta all'app si applica solo a:
- App che adottano Graph SDK.
- App che usano un accesso denominato HttpClient per l'API Graph che chiede agli utenti di fornire il consenso agli ambiti graph al primo accesso all'app.
Quando si usa un oggetto denominato HttpClient che non chiede agli utenti di fornire il consenso agli ambiti graph nel primo accesso, gli utenti vengono reindirizzati all'interfaccia utente di consenso di Azure per gli ambiti dell'API Graph quando richiedono per la prima volta l'accesso all'API Graph tramite il DelegatingHandler nome del preconfigurato.HttpClient Quando gli ambiti di Graph non vengono concessi inizialmente con l'approccio denominato HttpClient , né DefaultAccessTokenScopes AdditionalScopesToConsent vengono chiamati dall'app. Per altre informazioni, vedere la copertura denominata HttpClient
in questo articolo.
Soluzioni ospitate Blazor WebAssembly
Gli esempi in questo articolo riguardano l'uso di Graph SDK o un oggetto denominato HttpClient con l'API Graph direttamente da un'app autonoma Blazor WebAssembly o direttamente dall'app Client di una soluzione ospitataBlazor WebAssembly. Uno scenario aggiuntivo non trattato in questo articolo riguarda un'app Client di una soluzione ospitata per chiamare l'app Server della soluzione tramite l'API Web e quindi l'app Server usa Graph SDK/API per chiamare Microsoft Graph e restituire i dati all'app Client . Anche se si tratta di un approccio supportato, non è trattato in questo articolo. Se si vuole adottare questo approccio:
- Seguire le indicazioni riportate in Chiamare un'API Web da un'app ASP.NET Core Blazor per gli aspetti dell'API Web sull'emissione di richieste all'app Server dall'app Client e sulla restituzione dei dati all'appClient.
- Seguire le indicazioni nella documentazione principale di Microsoft Graph per usare Graph SDK con un'app tipica ASP.NET Core, che in questo scenario è l'app Server della soluzione. Se si usa il Blazor WebAssembly modello di progetto per creare la soluzione ospitata Blazor WebAssembly (ASP.NET Core Hosted
-h|--hosted
/) con autorizzazione organizzativa (singola organizzazione/SingleOrg
o più organizzazioni/MultiOrg
) e l'opzione Microsoft Graph (Piattaforma Microsoft identity>Connected Services>Aggiungere autorizzazioni Microsoft Graph in Visual Studio o l'opzione--calls-graph
con il comando dell'interfaccia della riga di comando di .NETdotnet new
), il Server l'app della soluzione è configurata per l'uso di Graph SDK quando la soluzione viene creata dal modello di progetto.
Risorse aggiuntive
Indicazioni generali
- Documentazione di Microsoft Graph
- App di esempio di Microsoft GraphBlazor WebAssembly: questo esempio illustra come usare Microsoft Graph .NET SDK per accedere ai dati in Office 365 dalle Blazor WebAssembly app.
- Creare app .NET con l'esercitazione su Microsoft Graph e l'esempio di Microsoft Graph ASP.NET'app Core: anche se queste risorse non si applicano direttamente a Graph dalle app latoBlazor WebAssembly client, la configurazione dell'app ME-ID e le procedure di codifica di Microsoft Graph nelle risorse collegate sono rilevanti per le app autonome Blazor WebAssembly e devono essere consultate per le procedure consigliate generali.
- Documentazione di Microsoft Graph
- App di esempio di Microsoft GraphBlazor WebAssembly: questo esempio illustra come usare Microsoft Graph .NET SDK per accedere ai dati in Office 365 dalle Blazor WebAssembly app.
- Creare app .NET con l'esercitazione su Microsoft Graph e l'esempio di Microsoft Graph ASP.NET'app Core: queste risorse sono più appropriate per le soluzioni ospitateBlazor WebAssembly, in cui l'app Server è configurata per accedere a Microsoft Graph come un'app ASP.NET Core tipica per conto dell'app.Client L'app Client usa l'API Web per effettuare richieste all'app per i Server dati graph. Anche se queste risorse non si applicano direttamente a Graph dalle app latoBlazor WebAssembly client, la configurazione dell'app ME-ID e le procedure di codifica di Microsoft Graph nelle risorse collegate sono rilevanti per le app autonome Blazor WebAssembly e devono essere consultate per le procedure consigliate generali.
Indicazioni sulla sicurezza
- Panoramica dell'autenticazione di Microsoft Graph
- Panoramica delle autorizzazioni di Microsoft Graph
- Riferimento alle autorizzazioni di Microsoft Graph
- Panoramica delle autorizzazioni e del consenso nella piattaforma Microsoft identity
- Migliorare la sicurezza con il principio dei privilegi minimi
- Articoli sull'escalation dei privilegi di Azure su Internet (risultato della ricerca Google)
- Procedure consigliate per la sicurezza Microsoft: protezione dell'accesso con privilegi