Partilhar via


Proteja um Blazor Web App ASP.NET Core com OpenID Connect (OIDC)

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Este artigo descreve como proteger um Blazor Web App com OpenID Connect (OIDC) usando um aplicativo de exemplo no repositório dotnet/blazor-samples GitHub (.NET 8 ou posterior) (como baixar).

Esta versão do artigo aborda a implementação do OIDC sem adotar o padrão Backend for Frontend (BFF). O padrão BFF é útil para fazer solicitações autenticadas para serviços externos. Altere o seletor de versão do artigo para OIDC com padrão BFF se a especificação do aplicativo exigir a adoção do padrão BFF.

A seguinte especificação é abrangida:

  • O Blazor Web App usa modo de renderização automática com interatividade global.
  • Os serviços personalizados do provedor de estado de autenticação são usados pelos aplicativos de servidor e cliente para capturar o estado de autenticação do usuário e fluí-lo entre o servidor e o cliente.
  • Este aplicativo é um ponto de partida para qualquer fluxo de autenticação OIDC. O OIDC é configurado manualmente no aplicativo e não depende de ID do Microsoft Entra ou pacotes de Web do Microsoft Identity, nem o aplicativo de exemplo requer hospedagem Microsoft Azure. No entanto, o aplicativo de exemplo pode ser usado com o Entra, o Microsoft Identity Web e hospedado no Azure.
  • Atualização automática de token que não requer interação.
  • Chama com segurança uma API (web) no projeto de servidor para obter dados.

Aplicativo de exemplo

O aplicativo de exemplo consiste em dois projetos:

  • BlazorWebAppOidc: Projeto do lado do servidor do Blazor Web App, contendo um exemplo API mínima ponto de extremidade para dados meteorológicos.
  • BlazorWebAppOidc.Client: Projeto do lado do cliente do Blazor Web App.

Acesse os aplicativos de exemplo através da pasta da versão mais recente a partir da raiz do repositório com o link a seguir. Os projetos estão na pasta BlazorWebAppOidc para .NET 8 ou posterior.

Exibir ou baixar código de exemplo (como baixar)

Projeto Blazor Web App do lado do servidor (BlazorWebAppOidc)

O projeto BlazorWebAppOidc é o projeto do lado do servidor do Blazor Web App.

O arquivo BlazorWebAppOidc.http pode ser usado para testar a solicitação de dados meteorológicos. Observe que o projeto BlazorWebAppOidc deve estar em execução para testar o ponto de extremidade e o ponto de extremidade é codificado no arquivo. Para obter mais informações, consulte Usar arquivos .http no Visual Studio 2022.

Observação

O projeto de servidor usa IHttpContextAccessor/HttpContext, mas nunca para componentes renderizados interativamente. Para obter mais informações, consulte as diretrizes de mitigação de ameaças para o ASP.NET Core Blazor de renderização interativa no lado do servidor.

Configuração

Esta seção explica como configurar o aplicativo de exemplo.

Observação

Para o Microsoft Entra ID ou Azure AD B2C, pode usar AddMicrosoftIdentityWebApp de Microsoft Identity Web, (Microsoft.Identity.Web pacote NuGet, documentação da API), que adiciona tanto os handlers de autenticação OIDC como Cookie com as definições padrão apropriadas. O aplicativo de exemplo e as diretrizes nesta seção não usam o Microsoft Identity Web. As instruções demonstram como configurar o manipulador OIDC manualmente para qualquer provedor OIDC. Para obter mais informações sobre como implementar o Microsoft Identity Web, consulte os recursos vinculados.

Estabeleça o segredo do cliente

Advertência

Não armazene segredos de aplicativos, cadeias de conexão, credenciais, senhas, números de identificação pessoal (PINs), código C#/.NET privado ou chaves/tokens privados no código do lado do cliente, que é sempre inseguro. Em ambientes de teste/preparação e produção, o código Blazor do lado do servidor e as APIs da Web devem usar fluxos de autenticação seguros que evitem a manutenção de credenciais no código do projeto ou nos arquivos de configuração. Fora dos testes de desenvolvimento local, recomendamos evitar o uso de variáveis de ambiente para armazenar dados confidenciais, pois as variáveis de ambiente não são a abordagem mais segura. Para testes de desenvolvimento local, a ferramenta Secret Manager é recomendada para proteger dados confidenciais. Para obter mais informações, consulte Manter com segurança dados confidenciais e credenciais.

Para testes de desenvolvimento local, use a ferramenta Secret Manager para armazenar o segredo do cliente do aplicativo de servidor sob a chave de configuração Authentication:Schemes:MicrosoftOidc:ClientSecret.

Observação

Se o aplicativo usa a ID do Microsoft Entra ou o Azure AD B2C, crie um segredo do cliente no registro do aplicativo no portal do Entra ou do Azure (Gerenciar Certificados>& segredos>Novo segredo do cliente). Use a Valor do novo segredo nas diretrizes a seguir.

O de aplicativo de exemplo de não foi inicializado para a ferramenta Gerenciador Secreto. Use um shell de comando, como o shell de comando do Developer PowerShell no Visual Studio, para executar o seguinte comando. Antes de executar o comando, altere o diretório com o comando cd para o diretório do projeto de servidor. O comando estabelece um identificador de segredos de usuário (<UserSecretsId> no arquivo de projeto do aplicativo de servidor):

dotnet user-secrets init

Execute o seguinte comando para definir o segredo do cliente. O marcador {SECRET} é o segredo do cliente obtido a partir do registo da aplicação:

dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}"

Se estiver usando o Visual Studio, você poderá confirmar que o segredo está definido clicando com o botão direito do mouse no projeto de servidor no Gerenciador de Soluções e selecionando Gerenciar Segredos de Usuário.

Configurar o aplicativo

A seguinte configuração OpenIdConnectOptions é encontrada no ficheiro Program do projeto durante a chamada para AddOpenIdConnect:

  • SignInScheme: Define o esquema de autenticação correspondente ao middleware responsável pela persistência do identity do usuário após uma autenticação bem-sucedida. O manipulador OIDC precisa usar um esquema de entrada que seja capaz de persistir as credenciais do usuário nas solicitações. A linha seguinte está presente apenas para fins de demonstração. Se omitido, DefaultSignInScheme é usado como um valor de fallback.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Escopos para openid e profile (Scope) (Opcional): Os escopos openid e profile também são configurados por padrão porque são necessários para que o manipulador OIDC funcione, mas podem precisar ser adicionados novamente se os escopos forem incluídos na configuração Authentication:Schemes:MicrosoftOidc:Scope. Para obter orientações gerais de configuração, consulte Configuração no ASP.NET Core e configuração no ASP.NET Core Blazor.

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: Define se os tokens de acesso e atualização devem ser armazenados no AuthenticationProperties após uma autorização bem-sucedida. Esta propriedade é definida como false para reduzir o tamanho do cookiede autenticação final.

    oidcOptions.SaveTokens = false;
    
  • Escopo para acesso offline (Scope): O escopo offline_access é necessário para o token de atualização.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Authority e ClientId: Define a Autoridade e a ID do Cliente para chamadas OIDC.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Exemplo:

    • Autoridade ({AUTHORITY}): https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/ (utiliza ID do Inquilino aaaabbbb-0000-cccc-1111-dddd2222eeee)
    • ID do Cliente ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
    oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
    

    Exemplo de autoridade "comum" do Microsoft Azure:

    A "autoridade comum" deve ser usada para aplicações multi-tenant. Você também pode usar a autoridade "comum" para aplicativos de locatário único, mas é necessário um IssuerValidator personalizado, conforme mostrado mais adiante nesta seção.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ResponseType: Configura o manipulador OIDC para executar apenas o fluxo de código de autorização. As subvenções implícitas e os fluxos híbridos são desnecessários neste modo.

    Na configuração de registro de aplicativo concessão implícita e fluxos híbridos do portal do Entra ou do Azure, configuração de registro de aplicativo, não marque a caixa de seleção do ponto de extremidade de autorização para retornar tokens do Access ou tokens de ID de . O manipulador OIDC solicita automaticamente os tokens apropriados usando o código retornado do endpoint de autorização.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaims e configuração de NameClaimType e RoleClaimType: Muitos servidores OIDC usam "name" e "role" em vez dos padrões SOAP /WS-Fed em ClaimTypes. Quando MapInboundClaims está definido como false, o manipulador não executa mapeamentos de declarações e os nomes de declaração do JWT são usados diretamente pelo aplicativo. O exemplo a seguir define o tipo de declaração de função como "roles", que é apropriado para Microsoft Entra ID (ME-ID). Consulte a documentação do seu fornecedor de identity para obter mais informações.

    Observação

    MapInboundClaims deve ser definido como false para a maioria dos provedores OIDC, o que impede a renomeação de declarações.

    oidcOptions.MapInboundClaims = false;
    oidcOptions.TokenValidationParameters.NameClaimType = "name";
    oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
    
  • Configuração de caminhos: os caminhos devem corresponder aos caminhos de URI de redirecionamento (caminho de retorno de chamada de login) e redirecionamento após término de sessão (caminho de retorno de chamada após término de sessão) configurados ao registrar a aplicação com o provedor OIDC. No portal do Azure, os caminhos são configurados no bloco Autenticação do registo do aplicativo. Os caminhos de entrada e saída devem ser registrados como URIs de redirecionamento. Os valores padrão são /signin-oidc e /signout-callback-oidc.

    • CallbackPath: O caminho da solicitação dentro do caminho base da aplicação a partir do qual o user-agent é retornado.

      No portal Entra ou Azure, defina o caminho na configuração de URI de Redirecionamento da plataforma Web nas opções .

      https://localhost/signin-oidc

      Observação

      Uma porta não é necessária para endereços localhost ao usar o Microsoft Entra ID. A maioria dos outros provedores OIDC requer uma porta correta.

    • SignedOutCallbackPath: O caminho de solicitação dentro do caminho base da aplicação em que o agente do utilizador é redirecionado após terminar sessão do provedor de identity.

      No portal do Entra ou do Azure, defina o caminho no URI de Redirecionamento da configuração da plataforma Web :

      https://localhost/signout-callback-oidc

      Observação

      Uma porta não é necessária para endereços localhost ao usar o Microsoft Entra ID. A maioria dos outros provedores OIDC requer uma porta correta.

      Observação

      Se estiver usando o Microsoft Identity Web, o provedor atualmente só redireciona de volta para o SignedOutCallbackPath se a Autoridade de microsoftonline.com (https://login.microsoftonline.com/{TENANT ID}/v2.0/) for usada. Essa limitação não existe se puderes usar a Autoridade "comum" com o Microsoft Identity Web. Para obter mais informações, consulte postLogoutRedirectUri não está funcionando quando a url da autoridade contém uma ID de locatário (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: As solicitações recebidas nesse caminho fazem com que o manipulador invoque a saída usando o esquema de saída.

      No portal do Entra ou do Azure, defina a URL de logout do canal Front-channel:

      https://localhost/signout-oidc

      Observação

      Uma porta não é necessária para endereços localhost ao usar o Microsoft Entra ID. A maioria dos outros provedores OIDC requer uma porta correta.

      oidcOptions.CallbackPath = new PathString("{PATH}");
      oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
      oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
      

      Exemplos (valores padrão):

      oidcOptions.CallbackPath = new PathString("/signin-oidc");
      oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
      oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
      
  • (Microsoft Azure apenas com o ponto de extremidade "comum") TokenValidationParameters.IssuerValidator: Muitos provedores OIDC trabalham com o validador de emissor padrão, mas precisamos levar em conta o emissor parametrizado com o ID do locatário ({TENANT ID}) retornado por https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration. Para obter mais informações, consulte SecurityTokenInvalidIssuerException com OpenID Connect e o endpoint "comum" do Azure AD (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731).

    Apenas para aplicações que utilizem o Microsoft Entra ID ou o Azure AD B2C com o endpoint "comum":

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

Exemplo de código do aplicativo

Inspecione o aplicativo de exemplo para os seguintes recursos:

  • Atualização automática de token não interativo com a ajuda de um atualizador cookie personalizado (CookieOidcRefresher.cs).
  • O projeto de servidor chama AddAuthenticationStateSerialization para adicionar um provedor de estado de autenticação do lado do servidor que usa PersistentComponentState para transferir o estado de autenticação para o cliente. O cliente chama AddAuthenticationStateDeserialization para desserializar e usar o estado de autenticação passado pelo servidor. O estado de autenticação é fixo para o tempo de vida do aplicativo WebAssembly.
  • Um exemplo de solicitações ao Blazor Web App para informações meteorológicas é tratado por um endpoint de API mínima (/weather-forecast) no arquivo Program (Program.cs). O endpoint requer autorização ao chamar RequireAuthorization. Para todos os controladores que você adicionar ao projeto, adicione o atributo [Authorize] ao controlador ou ação.
  • O aplicativo chama com segurança uma API (web) no projeto de servidor para dados meteorológicos:
    • Ao renderizar o componente Weather no servidor, o componente usa o ServerWeatherForecaster no servidor para obter dados meteorológicos diretamente (não por meio de uma chamada de API da Web).
    • Quando o componente é renderizado no cliente, o componente usa a implementação de serviço ClientWeatherForecaster, que usa uma HttpClient pré-configurada (no arquivo Program do projeto cliente) para fazer uma chamada de API da Web para o projeto de servidor. Um endpoint de API mínima (/weather-forecast) definido no ficheiro Program do projeto do servidor obtém os dados meteorológicos de ServerWeatherForecaster e retorna os dados ao cliente.
  • Atualização automática de tokens não interativos com a ajuda de um refrescador personalizado cookie (CookieOidcRefresher.cs).
  • A classe PersistingAuthenticationStateProvider (PersistingAuthenticationStateProvider.cs) é uma AuthenticationStateProvider do lado do servidor que usa PersistentComponentState para transmitir o estado de autenticação ao cliente, o qual é então mantido durante o tempo de vida da aplicação WebAssembly.
  • Um exemplo de pedido ao Blazor Web App para dados meteorológicos é tratado por um endpoint de API Minimal (/weather-forecast) no arquivo Program (Program.cs). O ponto de extremidade requer autorização chamando RequireAuthorization. Para todos os controladores que você adicionar ao projeto, adicione o atributo [Authorize] ao controlador ou ação.
  • O aplicativo chama com segurança uma API (web) no projeto de servidor para dados meteorológicos:
    • Ao renderizar o componente Weather no servidor, o componente usa o ServerWeatherForecaster no servidor para obter dados meteorológicos diretamente (não por meio de uma chamada de API da Web).
    • Quando o componente é renderizado no cliente, o componente usa a implementação de serviço ClientWeatherForecaster, que usa uma HttpClient pré-configurada (no arquivo Program do projeto cliente) para fazer uma chamada de API da Web para o projeto de servidor. Um endpoint de Minimal API (/weather-forecast) definido no ficheiro Program do projeto de servidor obtém os dados meteorológicos do ServerWeatherForecaster e retorna-os ao cliente.

Para obter mais informações sobre chamadas de API da Web usando abstrações de serviço em Blazor Web Apps, consulte Chamar uma API da Web de um aplicativo ASP.NET Core Blazor.

Projeto Blazor Web App do lado do cliente (BlazorWebAppOidc.Client)

O projeto BlazorWebAppOidc.Client é o projeto do lado cliente do Blazor Web App.

O cliente chama AddAuthenticationStateDeserialization para desserializar e usar o estado de autenticação passado pelo servidor. O estado de autenticação é fixo para o tempo de vida do aplicativo WebAssembly.

A classe PersistentAuthenticationStateProvider (PersistentAuthenticationStateProvider.cs) é um AuthenticationStateProvider do lado do cliente que determina o estado de autenticação do utilizador procurando dados persistentes na página quando é renderizada no servidor. O estado de autenticação é fixo para o tempo de vida do aplicativo WebAssembly.

Se o usuário precisar fazer login ou logout, será necessário um recarregamento de página inteira.

O aplicativo de exemplo fornece apenas um nome de usuário e e-mail para fins de exibição. Ele não inclui tokens que se autenticam no servidor ao fazer solicitações subsequentes, que funcionam separadamente usando um cookie incluído em HttpClient solicitações ao servidor.

Esta versão do artigo aborda a implementação do OIDC com o padrão Backend for Frontend (BFF). Altere o seletor de versão do artigo para OIDC sem padrão BFF se a especificação do aplicativo não exigir a adoção do padrão BFF.

A seguinte especificação é abrangida:

  • O Blazor Web App usa modo de renderização automática com interatividade global.
  • Os serviços personalizados do provedor de estado de autenticação são usados pelos aplicativos de servidor e cliente para capturar o estado de autenticação do usuário e fluí-lo entre o servidor e o cliente.
  • Este aplicativo é um ponto de partida para qualquer fluxo de autenticação OIDC. O OIDC é configurado manualmente no aplicativo e não depende de ID do Microsoft Entra ou pacotes de Web do Microsoft Identity, nem o aplicativo de exemplo requer hospedagem Microsoft Azure. No entanto, o aplicativo de exemplo pode ser usado com o Entra, o Microsoft Identity Web e hospedado no Azure.
  • Atualização de token automática e não interativa.
  • O padrão Backend for Frontend (BFF) é adotado usando o .NET Aspire para descoberta de serviços e YARP para solicitações de proxy para um ponto de extremidade de previsão do tempo no aplicativo de back-end.
    • Uma API Web de backend usa a autenticação JWT-bearer para validar tokens JWT salvos pelo Blazor Web App no cookiede início de sessão.
    • O Aspire melhora a experiência de criação de aplicações nativas da nuvem .NET. Ele fornece um conjunto consistente e opinativo de ferramentas e padrões para criar e executar aplicativos distribuídos.
    • YARP (Yet Another Reverse Proxy) é uma biblioteca usada para criar um servidor proxy reverso.

Para obter mais informações sobre .NET Aspire, consulte Disponibilidade geral do .NET Aspire: Simplificando o desenvolvimento do .NET Cloud-Native (maio, 2024).

Pré-requisito

.NET Aspire requer Visual Studio versão 17.10 ou posterior.

Aplicativo de exemplo

O aplicativo de exemplo consiste em cinco projetos:

  • .NET Aspire:
    • Aspire.AppHost: Usado para gerir as preocupações de orquestração de alto nível da aplicação.
    • Aspire.ServiceDefaults: Contém configurações padrão de aplicativos .NET Aspire que podem ser estendidas e personalizadas conforme necessário.
  • MinimalApiJwt: API de back-end da web, contendo um exemplo de Minimal API endpoint para dados meteorológicos.
  • BlazorWebAppOidc: Projeto do lado do servidor do Blazor Web App.
  • BlazorWebAppOidc.Client: Projeto do lado do cliente do Blazor Web App.

Acesse os aplicativos de exemplo através da pasta da versão mais recente a partir da raiz do repositório com o link a seguir. Os projetos estão na pasta BlazorWebAppOidcBff para .NET 8 ou posterior.

** Exibir ou baixar código de exemplo (como descarregar)

.NET Aspire projetos

Para obter mais informações sobre como usar o .NET Aspire e detalhes sobre os projetos de .AppHost e .ServiceDefaults do aplicativo de exemplo, consulte a documentação do .NET Aspire.

Confirme se você atendeu aos pré-requisitos para .NET Aspire. Para obter mais informações, consulte a seção Pré-requisitos de Início Rápido: crie a sua primeira aplicação .NET Aspire.

O aplicativo de exemplo configura apenas um perfil de inicialização HTTP inseguro (http) para uso durante o teste de desenvolvimento. Para obter mais informações, incluindo um exemplo de perfis de configurações de inicialização seguras e inseguras, consulte Permitir transporte não-seguro em .NET Aspire (documentação.NET Aspire).

Projeto Blazor Web App do lado do servidor (BlazorWebAppOidc)

O projeto BlazorWebAppOidc é o projeto de servidor do Blazor Web App. O projeto usa YARP para fazer proxy das solicitações para um endpoint de previsão do tempo no projeto de API da Web de backend (MinimalApiJwt) com o access_token armazenado no cookiede autenticação.

O arquivo BlazorWebAppOidc.http pode ser usado para testar a solicitação de dados meteorológicos. Observe que o projeto BlazorWebAppOidc deve estar em execução para testar o ponto de extremidade e o ponto de extremidade é codificado no arquivo. Para obter mais informações, consulte Usar arquivos .http no Visual Studio 2022.

Observação

O projeto de servidor usa IHttpContextAccessor/HttpContext, mas nunca para componentes renderizados interativamente. Para mais informações, consulte Diretrizes de mitigação de ameaças para ASP.NET Core Blazor de renderização interativa do lado do servidor.

Configuração

Esta seção explica como configurar o aplicativo de exemplo.

Observação

Para o Microsoft Entra ID ou Azure AD B2C, você pode usar AddMicrosoftIdentityWebApp de Microsoft Identity Web (Microsoft.Identity.Web pacote NuGetdocumentação da API), que adiciona os manipuladores de autenticação OIDC e Cookie com os padrões apropriados. O aplicativo de exemplo e as diretrizes nesta seção não usam o Microsoft Identity Web. As instruções demonstram como configurar o manipulador OIDC manualmente para um qualquer provedor OIDC. Para obter mais informações sobre como implementar o Microsoft Identity Web, consulte os recursos vinculados.

Estabeleça o segredo do cliente

Advertência

Não armazene segredos de aplicativos, cadeias de conexão, credenciais, senhas, números de identificação pessoal (PINs), código C#/.NET privado ou chaves/tokens privados no código do lado do cliente, que é sempre inseguro. Em ambientes de teste/preparação e produção, o código Blazor do lado do servidor e as APIs da Web devem usar fluxos de autenticação seguros que evitem a manutenção de credenciais no código do projeto ou nos arquivos de configuração. Fora dos testes de desenvolvimento local, recomendamos evitar o uso de variáveis de ambiente para armazenar dados confidenciais, pois as variáveis de ambiente não são a abordagem mais segura. Para testes de desenvolvimento local, a ferramenta Secret Manager é recomendada para proteger dados confidenciais. Para obter mais informações, consulte Manter com segurança dados confidenciais e credenciais.

Para testes de desenvolvimento local, use a ferramenta Secret Manager para armazenar o segredo do cliente do aplicativo de servidor sob a chave de configuração Authentication:Schemes:MicrosoftOidc:ClientSecret.

Observação

Se a app usa Microsoft Entra ID ou Azure AD B2C, crie um segredo do cliente no registo da app no portal do Entra ou do Azure (Gerir Certificados>& segredos>Novo segredo do cliente). Use o Valor do novo segredo nas diretrizes a seguir.

A aplicação de exemplo não foi inicializada para a ferramenta Gestor de Segredos. Use um shell de comando, como o shell de comando do Developer PowerShell no Visual Studio, para executar o seguinte comando. Antes de executar o comando, altere o diretório com o comando cd para o diretório do projeto de servidor. O comando estabelece um identificador de segredos de usuário (<UserSecretsId> no arquivo de projeto do aplicativo de servidor):

dotnet user-secrets init

Execute o seguinte comando para definir o segredo do cliente. O placeholder {SECRET} é o segredo do cliente obtido a partir do registo da aplicação.

dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}"

Se estiver usando o Visual Studio, você poderá confirmar que o segredo está definido clicando com o botão direito do mouse no projeto de servidor no Gerenciador de Soluções e selecionando Gerenciar Segredos de Usuário.

Configurar o aplicativo

A seguinte configuração OpenIdConnectOptions é encontrada no arquivo de Program do projeto na chamada para AddOpenIdConnect:

  • SignInScheme: Define o esquema de autenticação correspondente ao middleware responsável pela persistência do identity do usuário após uma autenticação bem-sucedida. O manipulador OIDC precisa usar um esquema de entrada que seja capaz de persistir as credenciais do usuário nas solicitações. A linha seguinte está presente apenas para fins de demonstração. Se omitido, DefaultSignInScheme é usado como um valor de fallback.

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • Escopos para openid e profile (Scope) (Opcional): Os escopos openid e profile também são configurados por padrão porque são necessários para que o manipulador OIDC funcione, mas podem precisar ser adicionados novamente se os escopos forem incluídos na configuração Authentication:Schemes:MicrosoftOidc:Scope. Para obter orientações gerais de configuração, consulte Configuração no ASP.NET Core e ASP.NETde configuração do Core Blazor .

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens: Define se os tokens de acesso e atualização devem ser armazenados no AuthenticationProperties após uma autorização bem-sucedida. O valor é definido como true para autenticar as solicitações de dados meteorológicos do projeto de API da Web de back-end (MinimalApiJwt).

    oidcOptions.SaveTokens = true;
    
  • Escopo para acesso offline (Scope): O escopo offline_access é necessário para o token de atualização.

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • Escopos para obter dados meteorológicos da API da Web (Scope): O escopo Weather.Get é configurado no portal Azure ou no portal Entra em Expor uma API. Isso é necessário para o projeto de API web de back-end (MinimalApiJwt) validar o token de acesso com o portador JWT.

    oidcOptions.Scope.Add("{APP ID URI}/{API NAME}");
    

    Exemplo:

    • URI da ID do aplicativo ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
      • Nome do Diretório ({DIRECTORY NAME}): contoso
      • ID do aplicativo (cliente) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    • Escopo configurado para dados meteorológicos de MinimalApiJwt ({API NAME}): Weather.Get
    oidcOptions.Scope.Add("https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444/Weather.Get");
    

    O exemplo anterior pertence a um aplicativo registrado em um locatário com um tipo de locatário B2C do AAD. Se a aplicação estiver registada num inquilino ME-ID, o URI da ID da aplicação será diferente; portanto, o alcance será diferente.

    Exemplo:

    • URI da ID do aplicativo ({APP ID URI}): api://{CLIENT ID} com ID do aplicativo (cliente) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    • Âmbito configurado para dados meteorológicos de MinimalApiJwt ({API NAME}): Weather.Get
    oidcOptions.Scope.Add("api://00001111-aaaa-2222-bbbb-3333cccc4444/Weather.Get");
    
  • Authority e ClientId: Define a Autoridade e a ID do Cliente para chamadas OIDC.

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    Exemplo:

    • Autoridade ({AUTHORITY}): https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/ (usa ID do Inquilino aaaabbbb-0000-cccc-1111-dddd2222eeee)
    • ID do Cliente ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
    oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
    

    Exemplo de autoridade "comum" do Microsoft Azure:

    A autoridade "comum" deve ser usada para aplicações multilocatário. Você também pode usar a autoridade "comum" para aplicativos de locatário único, mas é necessário um IssuerValidator personalizado, conforme mostrado mais adiante nesta seção.

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ResponseType: Configura o manipulador OIDC para executar apenas o fluxo de código de autorização. As subvenções implícitas e os fluxos híbridos são desnecessários neste modo.

    Na configuração de registro de aplicativo concessão implícita e fluxos híbridos do portal do Entra ou do Azure, configuração de registro de aplicativo, não marque a caixa de seleção do ponto de extremidade de autorização para retornar tokens do Access ou tokens de ID de . O manipulador OIDC solicita automaticamente os tokens apropriados usando o código retornado do endpoint de autorização.

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaims e configuração de NameClaimType e RoleClaimType: Muitos servidores OIDC usam "name" e "role" em vez dos padrões SOAP /WS-Fed em ClaimTypes. Quando MapInboundClaims é definido como false, o manipulador não executa mapeamentos de declarações e os nomes de declaração do JWT são usados diretamente pelo aplicativo. O exemplo a seguir define o tipo de declaração de função como "roles", que é apropriado para Microsoft Entra ID (ME-ID). Consulte a documentação do seu fornecedor de identity para obter mais informações.

    Observação

    MapInboundClaims deve ser definido como false para a maioria dos provedores OIDC, o que impede a renomeação de declarações.

    oidcOptions.MapInboundClaims = false;
    oidcOptions.TokenValidationParameters.NameClaimType = "name";
    oidcOptions.TokenValidationParameters.RoleClaimType = "roles";
    
  • Configuração de caminhos: Os caminhos devem corresponder ao URI de redirecionamento (caminho de retorno de chamada de login) e ao caminho de redirecionamento ao sair (caminho de retorno de chamada pós-desconexão) configurados ao registar a aplicação com o fornecedor OIDC. No portal do Azure, os caminhos são configurados no painel Autenticação do registo da aplicação. Os caminhos de entrada e saída devem ser registrados como URIs de redirecionamento. Os valores padrão são /signin-oidc e /signout-callback-oidc.

    • CallbackPath: O caminho da solicitação dentro do caminho base da aplicação onde o agente utilizador é devolvido.

      No portal do Entra ou do Azure, defina o caminho no URI de Redirecionamento da configuração da plataforma Web :

      https://localhost/signin-oidc

      Observação

      Uma porta não é necessária para localhost endereços.

    • SignedOutCallbackPath: O caminho da solicitação dentro do caminho base do aplicativo onde o agente do usuário é retornado após sair do provedor de identity.

      No portal Entra ou Azure, configure o caminho na configuração de plataforma Web na URI de Redirecionamento :

      https://localhost/signout-callback-oidc

      Observação

      Uma porta não é necessária para localhost endereços.

      Observação

      Se estiver usando o Microsoft Identity Web, o provedor atualmente só redireciona de volta para o SignedOutCallbackPath se a Autoridade de microsoftonline.com (https://login.microsoftonline.com/{TENANT ID}/v2.0/) for usada. Esta limitação não existe se for possível utilizar a Autoridade "comum" com Microsoft Identity Web. Para obter mais informações, consulte postLogoutRedirectUri não está funcionando quando a URL da autoridade contém um ID de inquilino (AzureAD/microsoft-authentication-library-for-js #5783).

    • RemoteSignOutPath: As solicitações recebidas nesse caminho fazem com que o manipulador invoque a saída usando o esquema de saída.

      No portal Entra ou Azure, defina a URL de encerramento de sessão do Front-channel :

      https://localhost/signout-oidc

      Observação

      Uma porta não é necessária para localhost endereços.

      oidcOptions.CallbackPath = new PathString("{PATH}");
      oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
      oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
      

      Exemplos (valores padrão):

      oidcOptions.CallbackPath = new PathString("/signin-oidc");
      oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
      oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
      
  • (Microsoft Azure apenas com o ponto de extremidade "comum") TokenValidationParameters.IssuerValidator: Muitos provedores OIDC trabalham com o validador de emissor padrão, mas precisamos levar em conta o emissor parametrizado com o ID do locatário ({TENANT ID}) retornado por https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration. Para obter mais informações, consulte SecurityTokenInvalidIssuerException com OpenID Connect e o endpoint "common" do Azure AD (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731).

    Apenas para aplicações que utilizam o Microsoft Entra ID ou o Azure AD B2C com o endpoint "comum":

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

Exemplo de código do aplicativo

Inspecione o aplicativo de exemplo para os seguintes recursos:

  • Atualização automática de token não interativo com a ajuda de um atualizador de cookie personalizado (CookieOidcRefresher.cs).
  • O projeto de servidor chama AddAuthenticationStateSerialization para adicionar um provedor de estado de autenticação do lado do servidor que usa PersistentComponentState para transferir o estado de autenticação ao cliente. O cliente chama AddAuthenticationStateDeserialization para desserializar e usar o estado de autenticação passado pelo servidor. O estado de autenticação é fixo para o tempo de vida do aplicativo WebAssembly.
  • As solicitações para o Blazor Web App são encaminhadas por proxy para o projeto de API web do back-end (MinimalApiJwt). MapForwarder no arquivo Program adiciona encaminhamento direto de solicitações HTTP que correspondem ao padrão especificado para um destino específico usando a configuração padrão para a solicitação de saída, transformações personalizadas e cliente HTTP padrão:
    • Ao renderizar o componente Weather no servidor, o componente usa o ServerWeatherForecaster para proxy da solicitação de dados meteorológicos com o token de acesso do usuário.
    • Quando o componente é renderizado no cliente, o componente usa a implementação de serviço ClientWeatherForecaster, que usa uma HttpClient pré-configurada (no arquivo Program do projeto cliente) para fazer uma chamada de API da Web para o projeto de servidor. Um ponto de extremidade de API mínima (/weather-forecast) definido no arquivo de Program do projeto de servidor transforma a solicitação com o token de acesso do usuário para obter os dados meteorológicos.
  • Atualização automática de token não interativo com a ajuda de um atualizador personalizado de cookie (CookieOidcRefresher.cs).
  • A classe PersistingAuthenticationStateProvider (PersistingAuthenticationStateProvider.cs) é uma AuthenticationStateProvider do lado do servidor que usa PersistentComponentState para transmitir o estado de autenticação ao cliente, que é então fixado para a duração de vida da aplicação WebAssembly.
  • As solicitações para o Blazor Web App são encaminhadas por proxy para o projeto de API web backend (MinimalApiJwt). MapForwarder no arquivo Program adiciona encaminhamento direto de solicitações HTTP que correspondem ao padrão especificado para um destino específico usando a configuração padrão para a solicitação de saída, transformações personalizadas e cliente HTTP padrão:
    • Ao renderizar o componente Weather no servidor, o componente usa o ServerWeatherForecaster para proxy da solicitação de dados meteorológicos com o token de acesso do usuário.
    • Quando o componente é renderizado no cliente, o componente usa a implementação de serviço ClientWeatherForecaster, que usa uma HttpClient pré-configurada (no arquivo Program do projeto cliente) para fazer uma chamada de API da Web para o projeto de servidor. Um endpoint de API mínima (/weather-forecast) definido no arquivo Program do projeto de servidor transforma a solicitação usando o token de acesso do usuário para obter os dados meteorológicos.

Para obter mais informações sobre chamadas de API (da Web) usando abstrações de serviço em Blazor Web Apps, consulte a secção para chamar uma API da Web de um aplicativo ASP.NET Core Blazor.

Projeto Blazor Web App do lado do cliente (BlazorWebAppOidc.Client)

O projeto BlazorWebAppOidc.Client é o projeto do lado cliente do Blazor Web App.

O cliente chama AddAuthenticationStateDeserialization para desserializar e usar o estado de autenticação passado pelo servidor. O estado de autenticação é fixo para o tempo de vida do aplicativo WebAssembly.

A classe PersistentAuthenticationStateProvider (PersistentAuthenticationStateProvider.cs) é um AuthenticationStateProvider do lado do cliente que determina o estado de autenticação do utilizador ao procurar dados armazenados na página quando esta foi renderizada no servidor. O estado de autenticação é fixo para o tempo de vida do aplicativo WebAssembly.

Se o usuário precisar fazer login ou logout, será necessário um recarregamento de página inteira.

O aplicativo de exemplo fornece apenas um nome de usuário e e-mail para fins de exibição. Ele não inclui tokens que se autenticam no servidor durante as solicitações subsequentes, funcionando separadamente ao utilizar um cookie, que é incluído nas solicitações HttpClient para o servidor.

Projeto de API web de back-end (MinimalApiJwt)

O projeto MinimalApiJwt é uma API web de back-end para vários projetos de frontend. O projeto configura um endpoint de API Minimal para dados meteorológicos. As solicitações do projeto do lado do servidor Blazor Web App (BlazorWebAppOidc) são intermediadas por proxy para o projeto MinimalApiJwt.

Configuração

Configure o projeto na JwtBearerOptions da invocação AddJwtBearer no ficheiro Program do projeto.

  • Audience: Define o destinatário para qualquer token OpenID Connect recebido.

    No portal do Azure ou do Entra: associe o valor apenas ao caminho do URI da ID de Aplicação configurado ao adicionar o âmbito Weather.Get em Expor uma API :

    jwtOptions.Audience = "{APP ID URI}";
    

    Exemplo:

    URI da ID do aplicativo ({APP ID URI}): https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}:

    • Nome do Diretório ({DIRECTORY NAME}): contoso
    • ID do aplicativo (cliente) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444
    jwtOptions.Audience = "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444";
    

    O exemplo anterior pertence a um aplicativo registrado em um locatário com um tipo de locatário B2C do AAD. Se o aplicativo estiver registrado em um locatário ME-ID, o URI da ID do aplicativo será diferente, portanto, o público será diferente.

    Exemplo:

    URI da ID do aplicativo ({APP ID URI}): api://{CLIENT ID} com ID do aplicativo (cliente) ({CLIENT ID}): 00001111-aaaa-2222-bbbb-3333cccc4444

    jwtOptions.Audience = "api://00001111-aaaa-2222-bbbb-3333cccc4444";
    
  • Authority: Define a autoridade para fazer chamadas OpenID Connect. Corresponda o valor à Autoridade configurada para o manipulador OIDC em BlazorWebAppOidc/Program.cs:

    jwtOptions.Authority = "{AUTHORITY}";
    

    Exemplo:

    Autoridade ({AUTHORITY}): https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/ (usa ID de Inquilino aaaabbbb-0000-cccc-1111-dddd2222eeee)

    jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/";
    

    O exemplo anterior refere-se a uma aplicação registada num inquilino com um tipo de inquilino B2C do AAD. Se a aplicação estiver registada num inquilino ME-ID, a autoridade deve corresponder ao emissor (iss) do JWT retornado pelo fornecedor de identity.

    jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/";
    

API mínima para dados meteorológicos

Ponto final seguro de dados de previsão do tempo no arquivo Program do projeto:

app.MapGet("/weather-forecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
}).RequireAuthorization();

O método de extensão RequireAuthorization requer autorização para a definição de rota. Para todos os controladores que você adicionar ao projeto, adicione o atributo [Authorize] ao controlador ou ação.

Redirecionar para a página de home ao terminar sessão

Quando um usuário navega pelo aplicativo, o componente LogInOrOut (Layout/LogInOrOut.razor) define um campo oculto para a URL de retorno (ReturnUrl) para o valor da URL atual (currentURL). Quando o utilizador termina sessão na aplicação, o fornecedor de identity devolve-o à página a partir da qual terminou sessão.

Se o usuário sair de uma página segura, ele retornará à mesma página segura depois de sair apenas para ser enviado de volta através do processo de autenticação. Esse comportamento é bom quando os usuários precisam mudar de conta com freqüência. No entanto, uma especificação de aplicação alternativa pode exigir que o utilizador seja encaminhado para a página home da aplicação ou para alguma outra página após terminar a sessão. O exemplo a seguir mostra como definir a página de home do aplicativo como a URL de retorno para operações de logout.

As alterações importantes no componente LogInOrOut são demonstradas no exemplo a seguir. Não há necessidade de fornecer um campo oculto para o ReturnUrl definido para a página home em / porque esse é o caminho padrão. IDisposable não é mais implementada. O NavigationManager já não é injetado. Todo o bloco @code é removido.

Layout/LogInOrOut.razor:

@using Microsoft.AspNetCore.Authorization

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout @context.User.Identity?.Name
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> 
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

Atualização de token

A implementação personalizada de atualização cookie (CookieOidcRefresher.cs) atualiza automaticamente as reivindicações de utilizador quando expiram. A implementação atual espera receber um token de identificação do endpoint do token em troca do token de atualização. As declarações nesse token de ID são usadas para substituir as declarações do usuário.

A implementação de exemplo não inclui código para solicitar reivindicações do endpoint UserInfo durante a atualização do token. Para obter mais informações, consulte BlazorWebAppOidc AddOpenIdConnect with GetClaimsFromUserInfoEndpoint = true doesn't propogate role claims to client (dotnet/aspnetcore #58826).

Observação

Alguns provedores de identity só retornam um token de acesso ao usar um token de renovação. O CookieOidcRefresher pode ser atualizado com lógica adicional para continuar a usar o conjunto anterior de declarações armazenadas no sistema de autenticação cookie ou para utilizar o token de acesso, a fim de solicitar declarações do UserInfo endpoint.

Nonce criptográfico

Um nonce é um valor alfanumérico que associa a sessão de um cliente a um token de identificação para mitigar ataques de repetição.

Se você receber um erro nonce durante o desenvolvimento e o teste de autenticação, use uma nova sessão do navegador InPrivate/incognito para cada execução de teste, não importa quão pequena seja a alteração feita no aplicativo ou no usuário de teste, pois dados cookie obsoletos podem levar a um erro nonce. Para obter mais informações, consulte a secção Cookies e dados do site.

Um nonce não é necessário ou usado quando um token de atualização é trocado por um novo token de acesso. No aplicativo de exemplo, o CookieOidcRefresher (CookieOidcRefresher.cs) deliberadamente define OpenIdConnectProtocolValidator.RequireNonce para false.

Funções de aplicativo para aplicativos não registrados no Microsoft Entra (ME-ID)

Esta secção refere-se a aplicações que não usam Microsoft Entra ID (ME-ID) como fornecedor de identity. Para aplicações registadas com ME-ID, consulte a secção Funções de aplicação para aplicações registadas no Microsoft Entra (ME-ID).

Configure o tipo de declaração de função (TokenValidationParameters.RoleClaimType) no OpenIdConnectOptions de Program.cs:

oidcOptions.TokenValidationParameters.RoleClaimType = "{ROLE CLAIM TYPE}";

Para muitos provedores OIDC de identity, o tipo de declaração de função é role. Verifique a documentação do seu fornecedor de identity para obter o valor correto.

Substitua a classe UserInfo no projeto BlazorWebAppOidc.Client pela classe a seguir.

UserInfo.cs:

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

namespace BlazorWebAppOidc.Client;

// Add properties to this class and update the server and client 
// AuthenticationStateProviders to expose more information about 
// the authenticated user to the client.
public sealed class UserInfo
{
    public required string UserId { get; init; }
    public required string Name { get; init; }
    public required string[] Roles { get; init; }

    public const string UserIdClaimType = "sub";
    public const string NameClaimType = "name";
    private const string RoleClaimType = "role";

    public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
        new()
        {
            UserId = GetRequiredClaim(principal, UserIdClaimType),
            Name = GetRequiredClaim(principal, NameClaimType),
            Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
                .ToArray(),
        };

    public ClaimsPrincipal ToClaimsPrincipal() =>
        new(new ClaimsIdentity(
            Roles.Select(role => new Claim(RoleClaimType, role))
                .Concat([
                    new Claim(UserIdClaimType, UserId),
                    new Claim(NameClaimType, Name),
                ]),
            authenticationType: nameof(UserInfo),
            nameType: NameClaimType,
            roleType: RoleClaimType));

    private static string GetRequiredClaim(ClaimsPrincipal principal,
        string claimType) =>
            principal.FindFirst(claimType)?.Value ??
            throw new InvalidOperationException(
                $"Could not find required '{claimType}' claim.");
}

Neste ponto, os componentes Razor podem adotar a autorização baseada em função e política . As funções do aplicativo aparecem em role declarações, uma declaração por função.

Funções de aplicativo para aplicativos registrados no Microsoft Entra (ME-ID)

Use as orientações nesta seção para implementar funções de aplicativo, ME-ID grupos de segurança e ME-ID funções de administrador internas para aplicativos que usam Microsoft Entra ID (ME-ID).

A abordagem descrita nesta seção configura ME-ID para enviar grupos e funções no cabeçalho de autenticação do cookie. Quando os usuários são apenas membros de alguns grupos e funções de segurança, a abordagem a seguir deve funcionar para a maioria das plataformas de hospedagem sem enfrentar um problema em que os cabeçalhos são muito longos, por exemplo, com a hospedagem do IIS que tem um limite de comprimento de cabeçalho padrão de 16 KB (MaxRequestBytes). Se o comprimento do cabeçalho for um problema devido à alta associação de grupo ou função, recomendamos não seguir as orientações nesta seção em favor da implementação do Microsoft Graph para obter, de forma separada, grupos e funções de um usuário de ME-ID, uma abordagem que não aumenta o tamanho do cabeçalho de autenticação cookie. Para obter mais informações, consulte Solicitação incorreta - Solicitação muito longa - Servidor IIS (dotnet/aspnetcore #57545).

Configure o tipo de declaração de função (TokenValidationParameters.RoleClaimType) em OpenIdConnectOptions de Program.cs. Defina o valor como roles:

oidcOptions.TokenValidationParameters.RoleClaimType = "roles";

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

Ao trabalhar com o diretório padrão, siga as orientações em Adicionar funções de aplicativo ao seu aplicativo e receba-as no token (ME-ID documentação) 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. Para obter mais informações, consulte Configurar a declaração de função (ME-ID documentação).

Os grupos de segurança do Azure de um usuário chegam em groups declarações, e as atribuições de função de administrador de ME-ID internas de um usuário chegam em declarações de IDs conhecidas (wids). Os valores para ambos os tipos de declaração são GUIDs. Quando recebidas pelo aplicativo, essas declarações podem ser usadas para estabelecer autorização de função e política em Razor componentes.

No manifesto do aplicativo no portal do Azure, defina o atributo groupMembershipClaims como All. Um valor de All resulta que ME-ID envia todos os grupos de segurança/distribuição (reivindicaçõesgroups) e funções (reivindicaçõeswids) do utilizador com sessão iniciada. Para definir o atributo groupMembershipClaims:

  1. Abra o registro do aplicativo no portal do Azure.
  2. Selecione Gerir>Manifesto na barra lateral.
  3. Encontre o atributo groupMembershipClaims.
  4. Defina o valor como All ("groupMembershipClaims": "All").
  5. Selecione o botão Salvar.

Substitua a classe UserInfo no projeto BlazorWebAppOidc.Client pela classe a seguir.

UserInfo.cs:

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

namespace BlazorWebAppOidc.Client;

// Add properties to this class and update the server and client 
// AuthenticationStateProviders to expose more information about 
// the authenticated user to the client.
public sealed class UserInfo
{
    public required string UserId { get; init; }
    public required string Name { get; init; }
    public required string[] Roles { get; init; }
    public required string[] Groups { get; init; }
    public required string[] Wids { get; init; }

    public const string UserIdClaimType = "sub";
    public const string NameClaimType = "name";
    private const string RoleClaimType = "roles";
    private const string GroupsClaimType = "groups";
    private const string WidsClaimType = "wids";

    public static UserInfo FromClaimsPrincipal(ClaimsPrincipal principal) =>
        new()
        {
            UserId = GetRequiredClaim(principal, UserIdClaimType),
            Name = GetRequiredClaim(principal, NameClaimType),
            Roles = principal.FindAll(RoleClaimType).Select(c => c.Value)
                .ToArray(),
            Groups = principal.FindAll(GroupsClaimType).Select(c => c.Value)
                .ToArray(),
            Wids = principal.FindAll(WidsClaimType).Select(c => c.Value)
                .ToArray(),
        };

    public ClaimsPrincipal ToClaimsPrincipal() =>
        new(new ClaimsIdentity(
            Roles.Select(role => new Claim(RoleClaimType, role))
                .Concat(Groups.Select(role => new Claim(GroupsClaimType, role)))
                .Concat(Wids.Select(role => new Claim(WidsClaimType, role)))
                .Concat([
                    new Claim(UserIdClaimType, UserId),
                    new Claim(NameClaimType, Name),
                ]),
            authenticationType: nameof(UserInfo),
            nameType: NameClaimType,
            roleType: RoleClaimType));

    private static string GetRequiredClaim(ClaimsPrincipal principal,
        string claimType) =>
            principal.FindFirst(claimType)?.Value ??
            throw new InvalidOperationException(
                $"Could not find required '{claimType}' claim.");
}

Neste ponto, os componentes Razor podem adotar autorização baseada em funções e em políticas:

  • As funções da aplicação aparecem nas reivindicações roles, uma reivindicação por função.
  • Os grupos de segurança aparecem em reivindicações groups, uma reivindicação por grupo. Os GUIDs do grupo de segurança aparecem no portal do Azure quando cria um grupo de segurança e são listados ao selecionar Visão geral Identity>>Grupos>Visualizar.
  • As funções de administrador internas do ME-ID aparecem numa declaração do wids, uma declaração por função. A reivindicação wids com um valor de b79fbf4d-3ef9-4689-8143-76b194e85509 é sempre enviada por ME-ID para contas não convidados do inquilino e não se refere a um papel de administrador. Os GUIDs de função de administrador (IDs de modelo de função) aparecem no portal do Azure ao selecionar Funções & administradores, seguidos pelas reticências (...) >Descrição para a função listada. As IDs dos modelos de função também estão listadas em funções internas do Microsoft Entra (documentação do Microsoft Entra).

Solução de problemas

Registo

O aplicativo de servidor é um aplicativo ASP.NET Core padrão. Consulte as diretrizes de registo do ASP.NET Core para habilitar um nível de registo mais baixo na aplicação de servidor.

Para habilitar o log de depuração ou rastreamento para autenticação Blazor WebAssembly, consulte a seção Log de autenticação do lado do cliente de ASP.NET de log do Core Blazor com o seletor de versão do artigo definido como ASP.NET Core 7.0 ou posterior.

Erros comuns

  • Configuração incorreta do aplicativo ou do provedor de Identity (IP)

    Os erros mais comuns são causados por configuração incorreta. Seguem-se alguns exemplos:

    • Dependendo dos requisitos do cenário, uma autoridade, instância, ID do locatário, domínio do locatário, ID do cliente ou URI de redirecionamento ausente ou incorreto impede que um aplicativo autentique clientes.
    • Escopos de solicitação incorretos impedem que os clientes acessem os endpoints da API Web do servidor.
    • Permissões incorretas ou ausentes da API do servidor impedem que os clientes acessem os pontos de extremidade da API da Web do servidor.
    • Executar a aplicação numa porta diferente da que está configurada na URI de redirecionamento do registo da aplicação do IP. Observe que uma porta não é necessária para o Microsoft Entra ID e um aplicativo em execução em um endereço de teste de desenvolvimento localhost, mas a configuração de porta do aplicativo e a porta onde o aplicativo está sendo executado devem corresponder para endereços nãolocalhost.

    A cobertura de configuração neste artigo mostra exemplos da configuração correta. Verifique cuidadosamente a configuração procurando por configuração incorreta de aplicativo e IP.

    Se a configuração parecer correta:

    • Analise os logs do aplicativo.

    • Examine o tráfego de rede entre o aplicativo cliente e o aplicativo IP ou servidor com as ferramentas de desenvolvedor do navegador. Muitas vezes, uma mensagem de erro exata ou uma mensagem com uma pista do que está causando o problema é retornada ao cliente pelo IP ou aplicativo de servidor depois de fazer uma solicitação. A orientação das ferramentas de desenvolvedor pode ser encontrada nos seguintes artigos:

    A equipa de documentação responde ao feedback sobre documentos e aos erros em artigos (abra um problema na secção Esta página de comentários), mas não pode fornecer suporte ao produto. Vários fóruns públicos de suporte estão disponíveis para ajudar na solução de problemas de um aplicativo. Recomendamos o seguinte:

    Os fóruns anteriores não pertencem nem são controlados pela Microsoft.

    Para relatórios de bugs de estrutura reproduzíveis que não sejam relacionados à segurança, nem sensíveis, nem confidenciais, registar uma questão com a unidade de produto ASP.NET Core. Não abra um problema com a unidade de produto até que você tenha investigado completamente a causa de um problema e não possa resolvê-lo sozinho e com a ajuda da comunidade em um fórum de suporte público. A unidade de produto não é capaz de solucionar problemas de aplicativos individuais que estão quebrados devido a simples erros de configuração ou casos de uso envolvendo serviços de terceiros. Se um relatório for de natureza sensível ou confidencial ou descrever uma possível falha de segurança no produto que os ciberatacantes podem explorar, consulte Relatando problemas de segurança e bugs (dotnet/aspnetcore repositório GitHub).

  • Cliente não autorizado para ME-ID

    info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Autorização falhou. Estes requisitos não foram atendidos: DenyAnonymousAuthorizationRequirement: Requer um usuário autenticado.

    Erro ao retornar a chamada de login do ME-ID:

    • Erro: unauthorized_client
    • Descrição: AADB2C90058: The provided application is not configured to allow public clients.

    Para resolver o erro:

    1. No portal do Azure, acesse o manifesto do aplicativo .
    2. Defina o atributo allowPublicClient como null ou true.

Cookies e dados do site

Os cookies e os dados do site podem persistir nas atualizações do aplicativo e interferir nos testes e na solução de problemas. Desmarque o seguinte ao fazer alterações no código do aplicativo, alterações na conta do usuário com o provedor ou alterações na configuração do aplicativo do provedor:

  • Cookies para iniciar sessão do utilizador
  • Cookies de aplicações
  • Dados do site em cache e armazenados

Uma abordagem para evitar que cookies persistentes e dados do site interfiram com testes e solução de problemas é:

  • Configurar um navegador
    • Use um navegador para testar que você pode configurar para excluir todos os dados cookie e do site sempre que o navegador for fechado.
    • Verifique se o navegador está fechado manualmente ou pelo IDE para qualquer alteração na configuração do aplicativo, do usuário de teste ou do provedor.
  • Use um comando personalizado para abrir um navegador no modo InPrivate ou de navegação anônima no Visual Studio:
    • Abra caixa de diálogo Procurar com no botão Executar do Visual Studio.
    • Selecione o botão Adicionar.
    • Forneça o caminho para o seu navegador no campo do programa. Os seguintes caminhos executáveis são locais de instalação típicos para o Windows 10. Se o seu navegador estiver instalado em um local diferente ou você não estiver usando o Windows 10, forneça o caminho para o executável do navegador.
      • Microsoft Edge: C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox: C:\Program Files\Mozilla Firefox\firefox.exe
    • No campo Argumentos, forneça a opção de linha de comando que o navegador usa para abrir no modo InPrivate ou no modo de navegação anónima. Alguns navegadores exigem o URL do aplicativo.
      • Microsoft Edge: Use -inprivate.
      • Google Chrome: use --incognito --new-window {URL}, onde o espaço reservado {URL} é o URL a ser aberto (por exemplo, https://localhost:5001).
      • Mozilla Firefox: Utilize -private -url {URL}, onde o espaço reservado {URL} é o URL a ser aberto (por exemplo, https://localhost:5001).
    • Forneça um nome no campo Nome amigável. Por exemplo, Firefox Auth Testing.
    • Selecione o botão OK.
    • Para evitar ter de selecionar o perfil do navegador para cada iteração de teste com uma aplicação, defina o perfil como predefinido com o botão Definir como Padrão.
    • Certifique-se de que o navegador está fechado pelo IDE para qualquer alteração na configuração do aplicativo, usuário de teste ou provedor.

Atualizações de aplicativos

Um aplicativo em funcionamento pode falhar imediatamente após atualizar o SDK do .NET Core na máquina de desenvolvimento ou alterar as versões do pacote no aplicativo. Em alguns casos, pacotes incoerentes podem quebrar um aplicativo ao executar grandes atualizações. A maioria desses problemas pode ser corrigida seguindo estas instruções:

  1. Limpe os caches de pacotes NuGet do sistema local executando dotnet nuget locals all --clear a partir de um shell de comando.
  2. Exclua as pastas bin e obj do projeto.
  3. Restaure e reconstrua o projeto.
  4. Exclua todos os arquivos na pasta de implantação no servidor antes de reimplantar o aplicativo.

Observação

Não há suporte para o uso de versões de pacote incompatíveis com a estrutura de destino do aplicativo. Para obter informações sobre um pacote, use a Galeria NuGet ou o FuGet Package Explorer .

Executar o aplicativo do servidor

Ao testar e solucionar problemas Blazor Web App, certifique-se de que você está executando o aplicativo a partir do projeto de servidor.

Inspecionar o usuário

O componente UserClaims a seguir pode ser usado diretamente em aplicativos ou servir como base para personalização adicional.

UserClaims.razor:

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Any())
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

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

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

Recursos adicionais