Grupos do Microsoft Entra (ME-ID), Funções de Administrador e Funções de Aplicativo (NET 5 ao .NET 7)

Observação

Esta não é a versão mais recente deste artigo. Quanto à versão atual do ASP.NET Core, consulte a versão mais recente do ASP.NET Core Blazor WebAssembly com grupos e funções de ID do Microsoft Entra.

Este artigo explica como configurar Blazor WebAssembly para usar grupos e funções do Microsoft Entra ID.

O Microsoft Entra (ME-ID) fornece várias abordagens de autorização que podem ser combinadas com ASP.NET Core Identity:

  • Grupos
    • Segurança
    • Microsoft 365
    • Distribuição
  • Funções
    • Funções de administrador do ME-ID
    • Funções de Aplicativo

As diretrizes neste artigo se aplicam aos cenários de implantação do ME-ID Blazor WebAssembly descritos nos seguintes artigos:

As diretrizes do artigo fornecem instruções para aplicativos cliente e servidor:

  • CLIENT: aplicativos Blazor WebAssembly autônomos ou o aplicativo Client de uma Blazorsolução hospedada.
  • SERVER: aplicativos de API web/API do servidor do ASP.NET Core ou o aplicativo Server de uma solução Blazor hospedada. Você pode ignorar as diretrizes do SERVER ao longo do artigo para um aplicativo Blazor WebAssembly autônomo.

Os exemplos deste artigo aproveitam os novos recursos do .NET/C#. Quando você usar os exemplos com o .NET 7 ou versões anteriores, pequenas modificações serão necessárias. No entanto, os exemplos de texto e código que pertencem à interação com o ME-ID e o Microsoft Graph são os mesmos para todas as versões do ASP.NET Core.

Pré-requisito

As diretrizes neste artigo implementam a API do Microsoft Graph de acordo com as diretrizes do SDK do Graph em Usar a API do Graph com ASP.NET Core Blazor WebAssembly. Siga as diretrizes de implementação do SDK do Graph para configurar o aplicativo e testá-lo para confirmar se o aplicativo pode obter dados da API do Graph para uma conta de usuário de teste. Além disso, consulte os links cruzados do artigo de segurança do artigo API do Graph para examinar os conceitos de segurança do Microsoft Graph.

Ao testar com o SDK do Graph localmente, recomendamos o uso de uma nova sessão do navegador InPrivate/incógnito para cada teste a fim de evitar que os cookies persistentes interfiram nos testes. Para obter mais informações, consulte Proteger um aplicativo autônomo ASP.NET Core Blazor WebAssembly com contas do Microsoft Entra ID.

Escopos

Para permitir chamadas à API do Microsoft Graph para dados de perfil de usuário, atribuição de função e associação de grupo:

  • Um aplicativo CLIENTE é configurado com o escopo delegado User.Read (https://graph.microsoft.com/User.Read) no portal do Azure porque o acesso aos dados de usuário de leitura é determinado pelos escopos concedidos (delegados) a usuários individuais.
  • Um aplicativo SERVIDOR é configurado com o escopo do aplicativo GroupMember.Read.All (https://graph.microsoft.com/GroupMember.Read.All) no portal do Azure porque o acesso é para o aplicativo obter informações sobre a associação a um grupo, não com base na autorização individual do usuário para acessar dados sobre membros do grupo.

Os escopos anteriores são necessários além dos escopos obrigatórios em cenários de implantação do ME-ID descritos pelos artigos listados anteriormente (Autônomo com Contas da Microsoft, Autônomo com ME-ID e Hospedado com ME-ID).

Para obter mais informações, consulte Visão geral das permissões e consentimento na plataforma de identity da Microsoft e Visão geral das permissões do Microsoft Graph.

Permissões e escopos significam a mesma coisa e são usados de forma intercambiável na documentação de segurança e no portal do Azure. A menos que o texto esteja se referindo ao portal do Azure, este artigo usa escopo/escopos ao se referir a permissões do Graph.

Os escopos não diferenciam maiúsculas de minúsculas, portanto, User.Read e user.read são a mesma coisa. Sinta-se à vontade para usar qualquer um dos formatos, mas recomendamos uma escolha consistente no código do aplicativo.

Atributo Declarações de associação de grupo

No manifesto do aplicativo no portal do Azure para aplicativos CLIENT e SERVER, defina o atributo groupMembershipClaims como DirectoryRole. Um valor de DirectoryRole resulta no ME-ID enviar todas as funções do usuário conectado na declaração de IDs conhecida (wids):

  1. Abra o registro do portal do Azure do aplicativo.
  2. Selecione Gerenciar>Manifesto na barra lateral.
  3. Localize o atributo groupMembershipClaims.
  4. Defina o valor como DirectoryRole ("groupMembershipClaims": "DirectoryRole").
  5. Selecione o botão Salvar se você fez alterações.

No manifesto do aplicativo no portal do Azure para aplicativos CLIENT e SERVER, defina o atributo groupMembershipClaims como All. Um valor de All resulta no envio pelo ME-ID de todos os grupos de segurança, grupos de distribuição e funções do usuário conectado na declaração de IDs conhecida (wids):

  1. Abra o registro do portal do Azure do aplicativo.
  2. Selecione Gerenciar>Manifesto na barra lateral.
  3. Localize o atributo groupMembershipClaims.
  4. Defina o valor como All ("groupMembershipClaims": "All").
  5. Selecione o botão Salvar se você fez alterações.

Conta de usuário personalizada

Atribua usuários a grupos de segurança do ME-ID e funções de administrador do ME-ID no portal do Azure.

Os exemplos neste artigo:

  • Pressupõem que um usuário seja atribuído à função Administrador de cobrança do ME-ID no locatário do ME-ID do portal do Azure para autorização para acessar dados da API do servidor.
  • Use políticas de autorização para controlar o acesso nos aplicativos CLIENT e SERVER.

No aplicativo CLIENT, estenda RemoteUserAccount para incluir propriedades para:

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

Adicione uma referência de pacote ao aplicativo CLIENT para Microsoft.Graph.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Adicione as classes e a configuração do utilitário do SDK do Graph nas diretrizes do SDK do Graph do artigo Usar A API do Graph com ASP.NET CoreBlazor WebAssembly. Especifique o escopo User.Read do token de acesso, como mostra o artigo em seu arquivo de exemplo wwwroot/appsettings.json.

Adicione a fábrica de contas de usuário personalizada a seguir ao aplicativo CLIENT. A fábrica de usuários personalizada é usada para estabelecer:

  • Declarações de Função de Aplicativo (appRole) (abordadas na seção Funções de Aplicativo).
  • Declarações de função de administrador do ME-ID (directoryRole).
  • Exemplo de declarações de dados de perfil de usuário para o número de telefone celular do usuário (mobilePhone) e o local do escritório (officeLocation).
  • Declarações de grupo do ME-ID (directoryGroup).
  • Um ILogger (logger) para conveniência, caso você deseje registrar informações ou erros.

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

O código anterior não inclui associações transitivas. Se o aplicativo exigir declarações de associação de grupo diretas e transitivas, substitua a propriedade MemberOf (IUserMemberOfCollectionWithReferencesRequestBuilder) por TransitiveMemberOf (IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder).

O código anterior ignora declarações de associação de grupo (groups) que são Funções de Administrador do ME-ID (tipo #microsoft.graph.directoryRole) porque os valores GUID retornados pelo ME-ID são IDs de entidade de função Administrador e não IDs de modelo de função. As IDs de entidade não são estáveis entre locatários e não devem ser usadas para criar políticas de autorização para usuários em aplicativos. Sempre use IDs de modelo para funções de administrador do ME-ID fornecidas por declarações wids.

A declaração wids (e, portanto, a declaração directoryRole) com um valor de b79fbf4d-3ef9-4689-8143-76b194e85509 existe para contas que não são de convidado do locatário. Ela não se refere a uma ID de Modelo de Função de Administrador do ME-ID.

No aplicativo CLIENT, configure a autenticação MSAL para usar o alocador de contas de usuário personalizado.

Confirme se o arquivo Program usa o namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Atualize a chamada AddMsalAuthentication para o seguinte. Observe que o RemoteUserAccount da estrutura Blazor é substituído pelo CustomUserAccount do aplicativo para a fábrica de entidades de segurança de declarações de conta e autenticação da MSAL:

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

Confirme a presença do código do SDK do Graph descrito pelo artigo Usar API do Graph com ASP.NET Core Blazor WebAssembly e se a configuração wwwroot/appsettings.json está correta de acordo com as diretrizes do SDK do Graph:

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

Configuração de autorização

No aplicativo CLIENTE, crie uma política para cada função de aplicativo, função de administrador ME-ID ou grupo de segurança no arquivo Program. O exemplo a seguir cria uma política para a função integrada Administrador de cobrança do ME-ID:

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

Para obter a lista completa de IDs para funções de administrador ME-ID, confira IDs de modelo de função na documentação do Entra. Para obter mais informações sobre as políticas de autorização, consulte Autorização baseada em política no ASP.NET Core.

Nos exemplos a seguir, o aplicativo CLIENT usa a política anterior para autorizar o usuário.

O componente AuthorizeView funciona com a política:

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

O acesso a um componente inteiro pode ser baseado na política usando uma diretiva de atributo [Authorize] (AuthorizeAttribute):

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

Se o usuário não estiver autorizado, ele será redirecionado para a página de entrada do ME-ID.

Uma verificação de política também pode ser executada no código com lógica de procedimento.

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 as abordagens anteriores, você também pode criar acesso baseado em política para funções de aplicativo, em que a GUID usada para a política é definido no elemento appRoles do manifesto do aplicativo no portal do Azure, e grupos de segurança, em que a GUID usada para a política corresponde à ID do objeto do grupo no painel Grupos do portal do Azure.

Autorizar o acesso à API Web/API do servidor

Um aplicativo de API SERVER pode autorizar os usuários a acessar pontos de extremidade de API seguros com políticas de autorização para grupos de segurança, Funções de Administrador do ME-ID e Funções de Aplicativo quando um token de acesso contém declarações groups, wids e role. O exemplo a seguir cria uma política para a função administrador de cobrança ME-ID no arquivo Program usando as declarações wids (IDs conhecidas/IDs de modelo de função):

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

Para obter a lista completa de IDs para Funções de Administrador do ME-ID, consulte IDs de modelo de função na documentação do Azure. Para obter mais informações sobre as políticas de autorização, consulte Autorização baseada em política no ASP.NET Core.

O acesso a um controlador no aplicativo SERVER pode ser baseado no uso de um atributo [Authorize] com o nome da política (documentação da API: AuthorizeAttribute).

O exemplo a seguir limita o acesso aos dados de cobrança do BillingDataController para administradores de cobrança do Azure com um nome de política de BillingAdministrator:

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

Para obter mais informações, consulte Autorização baseada em política no ASP.NET Core.

Funções de Aplicativo

Para configurar o aplicativo no portal do Microsoft Azure para fornecer declarações de associação de funções de aplicativo, consulte Adicionar funções de aplicativo ao seu aplicativo e recebê-las no token na documentação do Entra.

O exemplo a seguir pressupõe que os aplicativos CLIENT e SERVER estão configurados com duas funções atribuídas a um usuário de teste:

  • Admin
  • Developer

Observação

Ao desenvolver um aplicativo Blazor WebAssembly hospedado ou um par cliente-servidor de aplicativos autônomos (um aplicativo Blazor WebAssembly autônomo e um aplicativo de API web/API do servidor ASP.NET Core), a propriedade de manifesto appRoles dos registros de aplicativo do portal do Azure do cliente e do servidor deve incluir as mesmas funções configuradas. Depois de estabelecer as funções no manifesto do aplicativo cliente, copie-as na íntegra para o manifesto do aplicativo servidor. Se você não espelhar o manifesto appRoles entre os registros de aplicativo do cliente e do servidor, as declarações de função não serão estabelecidas para usuários autenticados da API do servidor/API Web, mesmo que seu token de acesso tenha as entradas corretas nas declarações.

Embora não seja possível atribuir funções a grupos sem uma conta Microsoft Entra ID Premium, você pode atribuir funções aos usuários e receber uma declaração para usuários com uma conta padrão do Azure. As diretrizes nesta seção não exigem uma conta Premium do ME-ID.

Ao trabalhar com o diretório padrão, siga as diretrizes em Adicionar funções de aplicativo a seu aplicativo e recebê-las no token para configurar e atribuir funções. Se você não estiver trabalhando com o diretório padrão, edite o manifesto do aplicativo no portal do Azure para estabelecer as funções do aplicativo manualmente na entrada appRoles do arquivo de manifesto. Veja a seguir uma entrada de exemplo appRoles que cria funções Admin e Developer. Essas funções de exemplo são usadas posteriormente no exemplo desta seção no nível do componente para implementar restrições de acesso:

"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"
  }
],

Para os {ADMIN GUID} espaços reservados e {DEVELOPER GUID} no exemplo anterior, você pode gerar GUIDs com um gerador de GUID online (resultado da pesquisa do Google para "gerador de guid")).

Para atribuir uma função a um usuário (ou grupo, se você tiver uma conta do Azure de camada Premium):

  1. Acesse Aplicativos empresariais na área do ME-ID do portal do Azure.
  2. Selecione o aplicativo. Selecione Gerenciar>Usuários e grupos na barra lateral.
  3. Marque a caixa de seleção para uma ou mais contas de usuário.
  4. No menu acima da lista de usuários, selecione Editar atribuição.
  5. Para a entrada Selecionar uma função, selecione Nenhuma selecionada.
  6. Escolha uma função na lista e use o botão Selecionar para selecioná-la.
  7. Use o botão Atribuir na parte inferior da tela para atribuir a função.

Várias funções são atribuídas no portal do Azure adicionando novamente um usuário para cada atribuição de função adicional. Use o botão Adicionar usuário/grupo na parte superior da lista de usuários para adicionar novamente um usuário. Use as etapas anteriores para atribuir outra função ao usuário. Você pode repetir esse processo quantas vezes forem necessárias para adicionar funções adicionais a um usuário (ou grupo).

O CustomAccountFactory mostrado na seção Conta de usuário personalizada é configurado para agir em uma declaração role com um valor de matriz JSON. Adicione e registre o CustomAccountFactory no aplicativo CLIENT, conforme mostrado na seção Conta de usuário personalizada. Não é necessário fornecer código para remover a declaração role original porque ela é removida automaticamente pela estrutura.

No arquivo Program de um aplicativo CLIENTE, especifique a declaração chamada "appRole" como a declaração de função para as verificações ClaimsPrincipal.IsInRole:

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

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

Observação

Se você preferir usar a declaração directoryRoles (Funções de Administrador ADD), atribua "directoryRoles" ao RemoteAuthenticationUserOptions.RoleClaim.

No arquivo Program de um aplicativo SERVIDOR, especifique a declaração chamada "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" como a declaração de função para verificações ClaimsPrincipal.IsInRole:

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

Observação

Quando um único esquema de autenticação é registrado, o esquema de autenticação é usado automaticamente como o esquema padrão do aplicativo e não é necessário declarar o esquema para AddAuthentication ou por meio de AuthenticationOptions. Para obter mais informações, consulte Visão geral da Autenticação ASP.NET Core e o comunicado de ASP.NET Core (aspnet/Announcements #490).

Observação

Se você preferir usar a declaração wids (Funções de Administrador ADD), atribua "wids" ao TokenValidationParameters.RoleClaimType.

Depois de concluir as etapas anteriores para criar e atribuir funções a usuários (ou grupos, se você tiver uma conta do Azure de camada Premium) e implementar o CustomAccountFactory com o SDK do Graph, conforme explicado anteriormente neste artigo e em Usar API do Graph com ASP.NET Core Blazor WebAssembly, você deverá ver uma declaração appRole para cada função atribuída à qual um usuário conectado é atribuído (ou funções atribuídas a grupos dos quais eles são membros). Execute o aplicativo com um usuário de teste para confirmar se as declarações estão presentes conforme o esperado. Ao testar com o SDK do Graph localmente, recomendamos o uso de uma nova sessão do navegador InPrivate/incógnito para cada teste a fim de evitar que os cookies persistentes interfiram nos testes. Para obter mais informações, consulte Proteger um aplicativo autônomo ASP.NET Core Blazor WebAssembly com contas do Microsoft Entra ID.

As abordagens de autorização de componentes estão funcionais neste momento. Qualquer um dos mecanismos de autorização em componentes do aplicativo CLIENT pode usar a função Admin para autorizar o usuário:

Há suporte para vários testes de função:

  • Exige que o usuário esteja na função Admin ou Developer com o componente AuthorizeView:

    <AuthorizeView Roles="Admin, Developer">
        ...
    </AuthorizeView>
    
  • Exige que o usuário esteja nas funções Admin e Developer com o componente AuthorizeView:

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

    Para obter mais informações no Context para AuthorizeView interno, confira autenticação e autorização Blazor do ASP.NET Core.

  • Exige que o usuário esteja na função Admin ou Developer com o atributo [Authorize]:

    @attribute [Authorize(Roles = "Admin, Developer")]
    
  • Exige que o usuário esteja nas funções Admin e Developer com o atributo [Authorize]:

    @attribute [Authorize(Roles = "Admin")]
    @attribute [Authorize(Roles = "Developer")]
    
  • Exige que o usuário esteja na função Admin ou Developer com o código de procedimento:

    @code {
        private async Task DoSomething()
        {
            var authState = await AuthenticationStateProvider
                .GetAuthenticationStateAsync();
            var user = authState.User;
    
            if (user.IsInRole("Admin") || user.IsInRole("Developer"))
            {
                ...
            }
            else
            {
                ...
            }
        }
    }
    
  • Exige que o usuário esteja nas funções Admin e Developer com o código de procedimento, alterando o OR condicional (||) para um AND condicional (&&) no exemplo anterior:

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

Qualquer um dos mecanismos de autorização em controladores do aplicativo SERVER pode usar a função Admin para autorizar o usuário:

Há suporte para vários testes de função:

  • Exige que o usuário esteja na função Admin ou Developer com o atributo [Authorize]:

    [Authorize(Roles = "Admin, Developer")]
    
  • Exige que o usuário esteja nas funções Admin e Developer com o atributo [Authorize]:

    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Developer")]
    
  • Exige que o usuário esteja na função Admin ou Developer com o código de procedimento:

    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 ...
    }
    
  • Exige que o usuário esteja nas funções Admin e Developer com o código de procedimento, alterando o OR condicional (||) para um AND condicional (&&) no exemplo anterior:

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

Como as comparações de cadeia de caracteres do .NET diferenciam maiúsculas de minúsculas por padrão, a correspondência entre nomes de função também diferencia maiúsculas de minúsculas. Por exemplo, Admin (A em maiúsculas) não é tratado como a mesma função que admin (a em minúsculas).

O caso Pascal normalmente é usado para nomes de função (por exemplo, BillingAdministrator), mas o uso do caso Pascal não é um requisito estrito. Diferentes esquemas de uso de maiúsculas e minúsculas, como maiúsculas e minúsculas concatenadas, kebab e snake são permitidos. O uso de espaços em nomes de função também é incomum, mas permitido. Por exemplo, billing administrator é um formato de nome de função incomum em aplicativos .NET, mas válido.

Recursos adicionais