Gruppi di Microsoft Entra (ME-ID), Ruoli di amministratore e Ruoli app (da .NET 5 a .NET 7)

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente di ASP.NET Core, vedere la versione più recente di ASP.NET Core Blazor WebAssembly con gruppi e ruoli di Microsoft Entra ID.

Questo articolo illustra come configurare Blazor WebAssembly per usare i gruppi e i ruoli di Microsoft Entra ID.

Microsoft Entra (ME-ID) offre diversi approcci di autorizzazione che possono essere combinati con ASP.NET Core Identity:

  • Gruppi
    • Sicurezza
    • Microsoft 365
    • Distribuzione
  • Ruoli
    • Ruoli di amministratore ME-ID
    • Ruoli dell'app

Le indicazioni contenute in questo articolo si applicano agli Blazor WebAssembly scenari di distribuzione ME-ID descritti negli articoli seguenti:

Le linee guida dell'articolo forniscono istruzioni per le app client e server:

  • CLIENT: app autonome Blazor WebAssembly o app Client di una soluzione ospitataBlazor.
  • SERVER: ASP.NET app API server core/API Web o l'app Server di una soluzione ospitata Blazor . È possibile ignorare il materiale sussidiario SERVER in tutto l'articolo relativo a un'app autonoma Blazor WebAssembly .

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 ME-ID e Microsoft Graph sono gli stessi per tutte le versioni di ASP.NET Core.

Prerequisito

Le indicazioni contenute in questo articolo implementano l'API Microsoft Graph per le linee guida di Graph SDK in Usare l'API Graph con ASP.NET CoreBlazor WebAssembly. Seguire le indicazioni sull'implementazione di Graph SDK per configurare l'app e testarla per verificare che l'app possa ottenere i dati dell'API Graph per un account utente di test. Vedere anche l'articolo sulla sicurezza dell'articolo sulla sicurezza dell'API Graph tra collegamenti per esaminare i concetti di sicurezza di Microsoft Graph.

Quando si esegue il test con Graph SDK in locale, è consigliabile usare una nuova sessione del browser in incognito/privata 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.

Ambiti

Per consentire le chiamate all'API Microsoft Graph per i dati di appartenenza a profili utente, assegnazione di ruolo e appartenenza a gruppi:

  • Un'app CLIENT viene configurata con l'ambito delegatoUser.Read (https://graph.microsoft.com/User.Read) nel portale di Azure perché l'accesso ai dati utente in lettura è determinato dagli ambiti concessi (delegati) ai singoli utenti.
  • Un'app SERVER è configurata con l'ambito dell'applicazione GroupMember.Read.All(https://graph.microsoft.com/GroupMember.Read.All) nel portale di Azure perché l'accesso è destinato all'app per ottenere informazioni sull'appartenenza ai gruppi, non in base all'autorizzazione utente singola per accedere ai dati relativi ai membri del gruppo.

Gli ambiti precedenti sono necessari oltre agli ambiti necessari negli scenari di distribuzione ME-ID descritti negli articoli elencati in precedenza (Standalone with Microsoft Accounts, Standalone with ME-ID e Hosted with ME-ID).

Per altre informazioni, vedere Panoramica delle autorizzazioni e del consenso nella piattaforma Microsoft identity e Panoramica delle autorizzazioni di Microsoft Graph.

Le autorizzazioni e gli 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.

Attributo Attestazioni di appartenenza al gruppo

Nel manifesto dell'app nella portale di Azure per le app CLIENT e SERVER impostare l'attributo groupMembershipClaims su .DirectoryRole Un valore di DirectoryRole restituisce ME-ID inviando tutti i ruoli dell'utente connesso nell'attestazione ID nota (wids):

  1. Aprire la registrazione portale di Azure dell'app.
  2. Selezionare Gestisci>manifesto nella barra laterale.
  3. Trovare l'attributo groupMembershipClaims .
  4. Impostare il valore su DirectoryRole ("groupMembershipClaims": "DirectoryRole").
  5. Selezionare il pulsante Salva se sono state apportate modifiche.

Nel manifesto dell'app nella portale di Azure per le app CLIENT e SERVER impostare l'attributo groupMembershipClaims su .All Un valore di All restituisce ME-ID inviando tutti i gruppi di sicurezza, i gruppi di distribuzione e i ruoli dell'utente connesso nell'attestazione ID noti (wids):

  1. Aprire la registrazione portale di Azure dell'app.
  2. Selezionare Gestisci>manifesto nella barra laterale.
  3. Trovare l'attributo groupMembershipClaims .
  4. Impostare il valore su All ("groupMembershipClaims": "All").
  5. Selezionare il pulsante Salva se sono state apportate modifiche.

Account utente personalizzato

Assegnare gli utenti ai gruppi di sicurezza ME-ID e ai ruoli di amministratore ME-ID nella portale di Azure.

Gli esempi in questo articolo:

  • Si supponga che un utente sia assegnato al ruolo Amministratore fatturazione ME-ID nel tenant portale di Azure ME-ID per l'autorizzazione ad accedere ai dati dell'API del server.
  • Usare i criteri di autorizzazione per controllare l'accesso all'interno delle app CLIENT e SERVER .

Nell'app CLIENT estendere RemoteUserAccount per includere le proprietà per:

  • Roles: matrice ruoli app ME-ID (descritta nella sezione Ruoli app)
  • Wids: ruoli di amministratore ME-ID nell'attestazione ID nota (wids)
  • Oid: attestazione dell'identificatore di oggetto non modificabile () (oididentifica in modo univoco un utente all'interno e tra i tenant)

CustomUserAccount.cs:

using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

namespace BlazorSample;

public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("roles")]
    public List<string>? Roles { get; set; }

    [JsonPropertyName("wids")]
    public List<string>? Wids { get; set; }

    [JsonPropertyName("oid")]
    public string? Oid { get; set; }
}

Aggiungere un riferimento al pacchetto all'app CLIENT per 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.

Aggiungere le classi di utilità e la configurazione di Graph SDK nelle linee guida per Graph SDK dell'articolo Usare l'API Graph con ASP.NET Core Blazor WebAssembly . Specificare l'ambito User.Read per il token di accesso come illustrato nell'articolo nel relativo file di esempio wwwroot/appsettings.json .

Aggiungere la factory dell'account utente personalizzata seguente all'app CLIENT . La factory utente personalizzata viene usata per stabilire:

  • Attestazioni del ruolo app () (appRoledescritte nella sezione Ruoli app).
  • Attestazioni del ruolo amministratore ME-ID (directoryRole).
  • Attestazioni di dati del profilo utente di esempio per il numero di telefono cellulare dell'utente (mobilePhone) e la posizione dell'ufficio (officeLocation).
  • Attestazioni del gruppo ME-ID (directoryGroup).
  • logger(ILogger) per praticità nel caso in cui si desideri registrare informazioni o errori.

CustomAccountFactory.cs:

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

namespace BlazorSample;

public class CustomAccountFactory() 
    : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    private readonly ILogger<CustomAccountFactory> logger;
    private readonly IServiceProvider serviceProvider;
    private readonly string? baseUrl =
        string.Join("/",
            config.GetSection("MicrosoftGraph")["BaseUrl"] ??
                "https://graph.microsoft.com",
            config.GetSection("MicrosoftGraph")["Version"] ??
                "v1.0");

    public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
        : base(accessor)
    {
        this.serviceProvider = serviceProvider;
        this.logger = logger;
    }

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount 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))
            {
                account?.Roles?.ForEach((role) =>
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                });

                account?.Wids?.ForEach((wid) =>
                {
                    userIdentity.AddClaim(new Claim("directoryRole", wid));
                });

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

                    var requestMemberOf = client.Users[account?.Oid].MemberOf;
                    var graphGroups = await requestMemberOf.GraphGroup.GetAsync();

                    if (graphGroups?.Value is not null)
                    {
                        foreach (var entry in graphGroups.Value)
                        {
                            if (entry.Id is not null)
                            {
                                userIdentity.AddClaim(
                                    new Claim("directoryGroup", entry.Id));
                            }
                        }
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

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

namespace BlazorSample;

public class CustomAccountFactory() 
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger;
    private readonly IServiceProvider serviceProvider;

    public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
        : base(accessor)
    {
        this.serviceProvider = serviceProvider;
        this.logger = logger;
    }

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount 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)
            {
                account?.Roles?.ForEach((role) =>
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                });

                account?.Wids?.ForEach((wid) =>
                {
                    userIdentity.AddClaim(new Claim("directoryRole", wid));
                });

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

                    var requestMemberOf = client.Users[account?.Oid].MemberOf;
                    var memberships = await requestMemberOf.Request().GetAsync();

                    if (memberships is not null)
                    {
                        foreach (var entry in memberships)
                        {
                            if (entry.ODataType == "#microsoft.graph.group")
                            {
                                userIdentity.AddClaim(
                                    new Claim("directoryGroup", entry.Id));
                            }
                        }
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Il codice precedente non include appartenenze transitive. Se l'app richiede attestazioni di appartenenza diretta e transitiva ai gruppi, sostituire la MemberOf proprietà (IUserMemberOfCollectionWithReferencesRequestBuilder) con TransitiveMemberOf (IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder).

Il codice precedente ignora le attestazioni di appartenenza al gruppo (groups) che sono ruoli di amministratore ME-ID (#microsoft.graph.directoryRole tipo) perché i valori GUID restituiti da ME-ID sono ID entità ruolo amministratore e non ID modello di ruolo. Gli ID entità non sono stabili tra i tenant e non devono essere usati per creare criteri di autorizzazione per gli utenti nelle app. Usare sempre gli ID modello per i ruoli di amministratore ME-ID forniti dalle wids attestazioni.

L'attestazione wids (e quindi directoryRole attestazione) con un valore di b79fbf4d-3ef9-4689-8143-76b194e85509 esiste per gli account non guest del tenant. Non fa riferimento a un ID del modello di ruolo amministratore ME-ID.

Nell'app CLIENT configurare l'autenticazione MSAL per usare la 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;

Aggiornare la AddMsalAuthentication chiamata al codice seguente. Si noti che il Blazor framework viene sostituito da quello dell'app RemoteUserAccount CustomUserAccount per l'autenticazione MSAL e la factory principale delle attestazioni dell'account:

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

Verificare la presenza del codice di Graph SDK descritto dall'articolo Usare l'API Graph con ASP.NET Core Blazor WebAssembly e che la wwwroot/appsettings.json configurazione sia corretta in base alle indicazioni di Graph SDK :

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

wwwroot/appsettings.json:

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

Configurazione dell'autorizzazione

Nell'app CLIENT creare un criterio per ogni ruolo app, ruolo amministratore ME-ID o gruppo di sicurezza nel Program file. L'esempio seguente crea un criterio per il ruolo Amministratore fatturazione predefinito ME-ID:

builder.Services.AddAuthorizationCore(options =>
{
    options.AddPolicy("BillingAdministrator", policy => 
        policy.RequireClaim("directoryRole", 
            "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});

Per l'elenco completo degli ID per i ruoli di amministratore ME-ID, vedere ID modello di ruolo nella documentazione di Entra. Per altre informazioni sui criteri di autorizzazione, vedere Autorizzazione basata su criteri in ASP.NET Core.

Negli esempi seguenti l'app CLIENT usa i criteri precedenti per autorizzare l'utente.

Il AuthorizeView componente funziona con i criteri:

<AuthorizeView Policy="BillingAdministrator">
    <Authorized>
        <p>
            The user is in the 'Billing Administrator' ME-ID Administrator Role
            and can see this content.
        </p>
    </Authorized>
    <NotAuthorized>
        <p>
            The user is NOT in the 'Billing Administrator' role and sees this
            content.
        </p>
    </NotAuthorized>
</AuthorizeView>

L'accesso a un intero componente può essere basato sui criteri usando una [Authorize] direttiva di attributo (AuthorizeAttribute):

@page "/"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "BillingAdministrator")]

Se l'utente non è autorizzato, viene reindirizzato alla pagina di accesso ME-ID.

È anche possibile eseguire un controllo dei criteri nel codice con logica procedurale.

CheckPolicy.razor:

@page "/checkpolicy"
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<h1>Check Policy</h1>

<p>This component checks a policy in code.</p>

<button @onclick="CheckPolicy">Check 'BillingAdministrator' policy</button>

<p>Policy Message: @policyMessage</p>

@code {
    private string policyMessage = "Check hasn't been made yet.";

    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task CheckPolicy()
    {
        var user = (await authenticationStateTask).User;

        if ((await AuthorizationService.AuthorizeAsync(user, 
            "BillingAdministrator")).Succeeded)
        {
            policyMessage = "Yes! The 'BillingAdministrator' policy is met.";
        }
        else
        {
            policyMessage = "No! 'BillingAdministrator' policy is NOT met.";
        }
    }
}

Usando gli approcci precedenti, è anche possibile creare l'accesso basato su criteri per i ruoli dell'app, in cui il GUID usato per i criteri viene impostato nell'elemento appRoles del manifesto dell'app nei gruppi di portale di Azure e di sicurezza, in cui il GUID usato per i criteri corrisponde all'ID oggetto gruppo nel riquadro gruppi di portale di Azure.

Autorizzare l'accesso api server/API Web

Un'app per le API SERVER può autorizzare gli utenti ad accedere agli endpoint API sicuri con criteri di autorizzazione per i gruppi di sicurezza, i ruoli di amministratore ME-ID e i ruoli dell'app quando un token di accesso contiene groupsattestazioni , widse role . L'esempio seguente crea un criterio per il ruolo Amministratore fatturazione ME-ID nel Program file usando le wids attestazioni (ID noti/ID modello di ruolo):

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("BillingAdministrator", policy => 
        policy.RequireClaim("wids", "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});

Per l'elenco completo degli ID per i ruoli di amministratore ME-ID, vedere ID modello di ruolo nella documentazione di Azure. Per altre informazioni sui criteri di autorizzazione, vedere Autorizzazione basata su criteri in ASP.NET Core.

L'accesso a un controller nell'app SERVER può essere basato sull'uso di un[Authorize] attributo con il nome del criterio (documentazione dell'API: AuthorizeAttribute).

L'esempio seguente limita l'accesso ai dati di fatturazione da BillingDataController agli amministratori di fatturazione di Azure con un nome di criterio :BillingAdministrator

using Microsoft.AspNetCore.Authorization;
[Authorize(Policy = "BillingAdministrator")]
[ApiController]
[Route("[controller]")]
public class BillingDataController : ControllerBase
{
    ...
}

Per altre informazioni, vedere Autorizzazione basata sui criteri in ASP.NET Core.

Ruoli dell'app

Per configurare l'app nella portale di Azure per fornire attestazioni di appartenenza ai ruoli dell'app, vedere Aggiungere ruoli dell'app all'applicazione e riceverli nel token nella documentazione di Entra.

L'esempio seguente presuppone che le app CLIENT e SERVER siano configurate con due ruoli e che i ruoli vengano assegnati a un utente di test:

  • Admin
  • Developer

Nota

Quando si sviluppa un'app ospitata Blazor WebAssembly o una coppia client-server di app autonome (un'app autonoma Blazor WebAssembly e un'app API server core/app PER LE API Web di ASP.NET), la appRoles proprietà manifesto sia del client che del server portale di Azure registrazioni dell'app deve includere gli stessi ruoli configurati. Dopo aver stabilito i ruoli nel manifesto dell'app client, copiarli interamente nel manifesto dell'app server. Se non si esegue il mirroring del manifesto appRoles tra le registrazioni dell'app client e server, le attestazioni del ruolo non vengono stabilite per gli utenti autenticati dell'API server/API Web, anche se il token di accesso contiene le voci corrette nelle attestazioni del ruolo.

Anche se non è possibile assegnare ruoli ai gruppi senza un account Microsoft Entra ID Premium, è possibile assegnare ruoli agli utenti e ricevere attestazioni di ruolo per gli utenti con un account Azure standard. Le indicazioni contenute in questa sezione non richiedono un account ME-ID Premium.

Quando si usa la directory predefinita, seguire le indicazioni riportate in Aggiungere ruoli dell'app all'applicazione e riceverli nel token per configurare e assegnare ruoli. Se non si usa la directory predefinita, modificare il manifesto dell'app nel portale di Azure per stabilire manualmente i ruoli dell'app nella appRoles voce del file manifesto. Di seguito è riportata una voce di esempio appRoles che crea Admin e Developer ruoli. Questi ruoli di esempio vengono usati più avanti nell'esempio di questa sezione a livello di componente per implementare le restrizioni di accesso:

"appRoles": [
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Administrators manage developers.",
    "displayName": "Admin",
    "id": "{ADMIN GUID}",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Admin"
  },
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Developers write code.",
    "displayName": "Developer",
    "id": "{DEVELOPER GUID}",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Developer"
  }
],

Per i {ADMIN GUID} segnaposto e {DEVELOPER GUID} nell'esempio precedente, è possibile generare GUID con un generatore GUID online (risultato della ricerca Google per "generatore guid").

Per assegnare un ruolo a un utente (o a un gruppo se si ha un account Azure di livello Premium):

  1. Passare ad Applicazioni aziendali nell'area ID ME del portale di Azure.
  2. Seleziona l'app. Selezionare Gestisci>utenti e gruppi dalla barra laterale.
  3. Selezionare la casella di controllo per uno o più account utente.
  4. Dal menu sopra l'elenco degli utenti selezionare Modifica assegnazione.
  5. Per la voce Selezionare un ruolo selezionare Nessuno selezionato.
  6. Scegliere un ruolo dall'elenco e usare il pulsante Seleziona per selezionarlo.
  7. Usare il pulsante Assegna nella parte inferiore della schermata per assegnare il ruolo.

Più ruoli vengono assegnati nel portale di Azure aggiungendo di nuovo un utente per ogni assegnazione di ruolo aggiuntiva. Usare il pulsante Aggiungi utente/gruppo nella parte superiore dell'elenco di utenti per aggiungere nuovamente un utente. Usare i passaggi precedenti per assegnare un altro ruolo all'utente. È possibile ripetere questo processo tutte le volte necessario per aggiungere altri ruoli a un utente (o a un gruppo).

La CustomAccountFactory sezione Account utente personalizzato è configurata per agire su un'attestazione role con un valore di matrice JSON. Aggiungere e registrare CustomAccountFactory nell'app CLIENT come illustrato nella sezione Account utente personalizzato. Non è necessario fornire codice per rimuovere l'attestazione originale role perché viene rimossa automaticamente dal framework.

Program Nel file di un'app CLIENT specificare l'attestazione denominata "appRole" come attestazione del ruolo per ClaimsPrincipal.IsInRole i controlli:

builder.Services.AddMsalAuthentication(options =>
{
    ...

    options.UserOptions.RoleClaim = "appRole";
});

Nota

Se si preferisce usare l'attestazione directoryRoles (ADD Administrator Roles), assegnare "directoryRoles" a RemoteAuthenticationUserOptions.RoleClaim.

Program Nel file di un'app SERVER specificare l'attestazione denominata "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" come attestazione del ruolo per ClaimsPrincipal.IsInRole i controlli:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(options =>
    {
        Configuration.Bind("AzureAd", options);
        options.TokenValidationParameters.RoleClaimType = 
            "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
    },
    options => { Configuration.Bind("AzureAd", options); });

Nota

Quando viene registrato un singolo schema di autenticazione, lo schema di autenticazione viene usato automaticamente come schema predefinito dell'app e non è necessario dichiarare lo schema a AddAuthentication o tramite AuthenticationOptions. Per altre informazioni, vedere Panoramica dell'autenticazione principale di ASP.NET e dell'annuncio di ASP.NET Core (aspnet/Announcements #490).

Nota

Se si preferisce usare l'attestazione wids (ADD Administrator Roles), assegnare "wids" a TokenValidationParameters.RoleClaimType.

Dopo aver completato i passaggi precedenti per creare e assegnare ruoli agli utenti (o ai gruppi se si dispone di un account Azure di livello Premium) e aver implementato CustomAccountFactory con Graph SDK, come illustrato in precedenza in questo articolo e in Usare l'API Graph con ASP.NET Core Blazor WebAssembly, dovrebbe essere visualizzata un'attestazione appRole per ogni ruolo assegnato a un utente connesso (o ruoli assegnati a gruppi di cui sono membri). Eseguire l'app con un utente di test per verificare che le attestazioni siano presenti come previsto. Quando si esegue il test con Graph SDK in locale, è consigliabile usare una nuova sessione del browser in incognito/privata 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 approcci di autorizzazione dei componenti sono funzionali a questo punto. Uno dei meccanismi di autorizzazione nei componenti dell'app CLIENT può usare il Admin ruolo per autorizzare l'utente:

Sono supportati più test di ruolo:

  • Richiedere che l'utente sia nel Admin ruolo o Developer con il AuthorizeView componente :

    <AuthorizeView Roles="Admin, Developer">
        ...
    </AuthorizeView>
    
  • Richiedere che l'utente sia in entrambi i Admin ruoli e Developer con il AuthorizeView componente:

    <AuthorizeView Roles="Admin">
        <AuthorizeView Roles="Developer" Context="innerContext">
            ...
        </AuthorizeView>
    </AuthorizeView>
    

    Per altre informazioni su per l'interfaccia Context interna, vedere ASP.NET'autenticazione e autorizzazione core Blazor AuthorizeView.

  • Richiedere che l'utente sia nel Admin ruolo o Developer con l'attributo :[Authorize]

    @attribute [Authorize(Roles = "Admin, Developer")]
    
  • Richiedere che l'utente sia in entrambi i ruoli e Developer con l'attributo [Authorize] :Admin

    @attribute [Authorize(Roles = "Admin")]
    @attribute [Authorize(Roles = "Developer")]
    
  • Richiedere che l'utente sia nel ruolo o Developer con codice Admin procedurale:

    @code {
        private async Task DoSomething()
        {
            var authState = await AuthenticationStateProvider
                .GetAuthenticationStateAsync();
            var user = authState.User;
    
            if (user.IsInRole("Admin") || user.IsInRole("Developer"))
            {
                ...
            }
            else
            {
                ...
            }
        }
    }
    
  • Richiedere che l'utente sia in entrambi i ruoli e Developer con codice procedurale modificando l'OR condizionale (||) in un AND condizionale (&&) nell'esempio precedente:Admin

    if (user.IsInRole("Admin") && user.IsInRole("Developer"))
    

Uno dei meccanismi di autorizzazione nei controller dell'app SERVER può usare il Admin ruolo per autorizzare l'utente:

Sono supportati più test di ruolo:

  • Richiedere che l'utente sia nel Admin ruolo o Developer con l'attributo :[Authorize]

    [Authorize(Roles = "Admin, Developer")]
    
  • Richiedere che l'utente sia in entrambi i ruoli e Developer con l'attributo [Authorize] :Admin

    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Developer")]
    
  • Richiedere che l'utente sia nel ruolo o Developer con codice Admin procedurale:

    static readonly string[] scopeRequiredByApi = new string[] { "API.Access" };
    
    ...
    
    [HttpGet]
    public IEnumerable<ReturnType> Get()
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
    
        if (User.IsInRole("Admin") || User.IsInRole("Developer"))
        {
            ...
        }
        else
        {
            ...
        }
    
        return ...
    }
    
  • Richiedere che l'utente sia in entrambi i ruoli e Developer con codice procedurale modificando l'OR condizionale (||) in un AND condizionale (&&) nell'esempio precedente:Admin

    if (User.IsInRole("Admin") && User.IsInRole("Developer"))
    

Poiché i confronti tra stringhe .NET fanno distinzione tra maiuscole e minuscole, anche i nomi dei ruoli corrispondenti fanno distinzione tra maiuscole e minuscole. Ad esempio, Admin (maiuscolo A) non viene considerato come lo stesso ruolo di admin (minuscolo a).

Il caso Pascal viene in genere usato per i nomi dei ruoli ,ad esempio BillingAdministrator, ma l'uso del caso Pascal non è un requisito rigoroso. Sono consentiti diversi schemi di maiuscole e minuscole, come il case camel, il kebab case e il caso serpente. Anche l'uso di spazi nei nomi dei ruoli è insolito ma consentito. Ad esempio, billing administrator è un formato di nome di ruolo insolito nelle app .NET, ma valido.

Risorse aggiuntive