Proteja um ASP.NET Core Blazor Web App com o Microsoft Entra ID
Este artigo descreve como proteger um Blazor Web App com Microsoft Identity Platform/pacotes Web do Microsoft Identity para do Microsoft Entra ID usando um aplicativo de exemplo.
A seguinte especificação é abrangida:
- O Blazor Web App usa o modo de renderização automática com interatividade global (
InteractiveAuto
). - O projeto de servidor chama AddAuthenticationStateSerialization para adicionar um fornecedor de estado de autenticação do lado do servidor que utiliza PersistentComponentState para transmitir 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.
- A aplicação usa Microsoft Entra ID, com base em pacotes de Microsoft Identity Web.
- A atualização automática de tokens não interativos é gerida pelo framework.
- O aplicativo usa abstrações de serviço do lado do servidor e do lado do cliente para exibir dados meteorológicos gerados:
- Ao renderizar o componente
Weather
no servidor para exibir dados meteorológicos, o componente usa oServerWeatherForecaster
no servidor para obter diretamente dados meteorológicos (não por meio de uma chamada de API da Web). - Quando o componente
Weather
é renderizado no cliente, o componente usa a implementação de serviçoClientWeatherForecaster
, que usa uma HttpClient pré-configurada (no arquivoProgram
do projeto cliente) para fazer uma chamada de API da Web para a API mínima (/weather-forecast
) do projeto de servidor para dados meteorológicos. O ponto de extremidade da API Minimal obtém os dados meteorológicos da classeServerWeatherForecaster
e os retorna ao cliente para processamento pelo componente.
- Ao renderizar o componente
Aplicativo de exemplo
O aplicativo de exemplo consiste em dois projetos:
-
BlazorWebAppEntra
: Projeto lado servidor do Blazor Web App, contendo um exemplo de API mínima endpoint para dados meteorológicos. -
BlazorWebAppEntra.Client
: Projeto do lado do cliente do Blazor Web App.
Aceda às aplicações de exemplo na pasta da versão mais recente desde a raiz do repositório com o link a seguir. Os projetos estão na pasta BlazorWebAppEntra
para .NET 9 ou posterior.
Ver ou baixar código de amostra (como baixar)
Projeto Blazor Web App do lado do servidor (BlazorWebAppEntra
)
O projeto BlazorWebAppEntra
é o projeto do lado do servidor do Blazor Web App.
O arquivo BlazorWebAppEntra.http
pode ser usado para testar a solicitação de dados meteorológicos. Observe que o projeto BlazorWebAppEntra
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.
Projeto do lado do cliente Blazor Web App (BlazorWebAppEntra.Client
)
O projeto BlazorWebAppEntra.Client
é o projeto cliente do Blazor Web App.
Se o usuário precisar fazer login ou logout durante a renderização do lado do cliente, uma recarga de página inteira será iniciada.
Configuração
Esta seção explica como configurar o aplicativo de exemplo.
AddMicrosoftIdentityWebApp
Microsoft Identity Web (Microsoft.Identity.Web
pacote NuGet, documentação da API) é configurada pela seção AzureAd
do arquivo de appsettings.json
do projeto de servidor.
No registro do aplicativo no portal do Entra ou do Azure, use uma configuração de plataforma de Web com um de URI de Redirecionamento de https://localhost/signin-oidc
(uma porta não é necessária). Confirme se tokens de ID e tokens de acesso em Concessão implícita e fluxos híbridosnão estão selecionados. O manipulador OpenID Connect solicita automaticamente os tokens apropriados usando o código retornado do endpoint de autorização.
Configurar o aplicativo
No arquivo de configurações do aplicativo do projeto de servidor (appsettings.json
), forneça a configuração da seção AzureAd
do aplicativo. Obtenha o ID da aplicação (cliente), o domínio do locatário (editor) e o ID do diretório (locatário) a partir do registo da aplicação no portal Entra ou Azure:
"AzureAd": {
"CallbackPath": "/signin-oidc",
"ClientId": "{CLIENT ID}",
"Domain": "{DOMAIN}",
"Instance": "https://login.microsoftonline.com/",
"ResponseType": "code",
"TenantId": "{TENANT ID}"
},
Marcadores de posição no exemplo anterior:
-
{CLIENT ID}
: O ID do aplicativo (cliente). -
{DOMAIN}
: O domínio do locatário, ou seja, o editor. -
{TENANT ID}
: O ID do diretório (inquilino).
Exemplo:
"AzureAd": {
"CallbackPath": "/signin-oidc",
"ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
"Domain": "contoso.onmicrosoft.com",
"Instance": "https://login.microsoftonline.com/",
"ResponseType": "code",
"TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
},
O caminho do retorno de chamada (CallbackPath
) deve corresponder ao URI de redirecionamento (caminho de retorno de chamada do início de sessão) configurado ao registar a aplicação no portal Entra ou Azure. Os caminhos são configurados na secção Autenticação do registo do aplicativo. O valor padrão de CallbackPath
é /signin-oidc
para um URI de redirecionamento registrado de https://localhost/signin-oidc
(uma porta não é necessária).
O SignedOutCallbackPath (chave de configuração: "SignedOutCallbackPath
") é o caminho da solicitação dentro do caminho base do aplicativo intercetado pelo manipulador OpenID Connect onde o agente do usuário é retornado pela primeira vez após sair do Entra. O aplicativo de exemplo não define um valor para o caminho porque o valor padrão de "/signout-callback-oidc
" é usado. Depois de intercetar a solicitação, o manipulador OpenID Connect redireciona para o SignedOutRedirectUri ou RedirectUri, se especificado.
Configure o caminho de retorno de chamada de sessão terminada no registo do Entra da aplicação. No portal do Entra ou do Azure, defina o caminho nas entradas de de 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 Entra.
Se não adicionares o URI do caminho de retorno de chamada após a desconexão ao registo da aplicação no Entra, o Entra recusa-se a redirecionar o utilizador de volta para a aplicação e apenas pede que ele feche a janela do navegador.
Observação
O Entra não redireciona um usuário administrador principal (conta root) ou usuário externo de volta para o aplicativo Blazor. Em vez disso, o Entra desconecta o usuário do aplicativo e recomenda que ele feche todas as janelas do navegador. 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).
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.
Definir o segredo de cliente
Crie um segredo do cliente no registro do Entra ID do aplicativo no portal do Entra ou do Azure (Gerenciar Certificados>& segredos>Novo segredo do cliente). Use o Valor do novo segredo na seguinte diretriz.
Use uma ou ambas as seguintes abordagens para fornecer o segredo do cliente ao aplicativo:
- ferramenta Secret Manager: A ferramenta Secret Manager armazena dados privados na máquina local e só é usada durante o desenvolvimento local.
- Azure Key Vault: Você pode armazenar o segredo do cliente em um cofre de chaves para uso em qualquer ambiente, inclusive para o ambiente de desenvolvimento ao trabalhar localmente. Alguns programadores preferem utilizar cofres de chaves para implementações de teste e produção e utilizar a ferramenta Secret Manager para desenvolvimento local.
É altamente recomendável evitar armazenar segredos do cliente no código do projeto ou em arquivos de configuração. Use fluxos de autenticação seguros, como uma ou ambas as abordagens nesta seção.
Ferramenta Secret Manager
A ferramenta Secret Manager pode armazenar o segredo do cliente do aplicativo de servidor sob a chave de configuração AzureAd:ClientSecret
.
O aplicativo de exemplo não foi inicializado 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, que é usado internamente pelas ferramentas para rastrear segredos para o aplicativo:
dotnet user-secrets init
Execute o seguinte comando para definir o segredo do cliente. O marcador de posição {SECRET}
é o segredo do cliente obtido no registo Entra da aplicação:
dotnet user-secrets set "AzureAd:ClientSecret" "{SECRET}"
Se estiver usando o Visual Studio, você pode confirmar que o segredo está definido clicando com o botão direito do mouse no projeto de servidor em Gerenciador de Soluções e selecionando Gerenciar Segredos de Usuário.
Azure Key Vault
Azure Key Vault fornece uma abordagem segura para disponibilizar o segredo do cliente da aplicação à própria aplicação.
Para criar um cofre de chaves e definir um segredo do cliente, consulte Sobre segredos do Cofre de Chaves do Azure (documentação do Azure), que vincula recursos para começar a usar o Cofre de Chaves do Azure. Para implementar o código nesta seção, registre o URI do cofre de chaves e o nome secreto do Azure ao criar o cofre de chaves e o segredo. Quando você define a política de acesso para o segredo no painel Políticas de acesso:
- Apenas a permissão secreta Obter é necessária.
- Selecione o aplicativo como o Principal para o segredo.
Importante
Um segredo do cofre de chaves é criado com uma data de validade. Certifique-se de controlar quando um segredo do cofre de chaves vai expirar e crie um novo segredo para o aplicativo antes que essa data passe.
Adicione a seguinte classe AzureHelper
ao projeto de servidor. O método GetKeyVaultSecret
recupera um segredo de um cofre de chaves. Ajuste o namespace (BlazorSample.Helpers
) para corresponder ao esquema de namespace do projeto.
Helpers/AzureHelper.cs
:
using Azure;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace BlazorSample.Helpers;
public static class AzureHelper
{
public static string GetKeyVaultSecret(string tenantId, string vaultUri, string secretName)
{
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = tenantId,
SharedTokenCacheTenantId = tenantId
};
var client = new SecretClient(new Uri(vaultUri), new DefaultAzureCredential(options));
var secret = client.GetSecretAsync(secretName).Result;
return secret.Value.Value;
}
}
Onde os serviços são registrados no arquivo de Program
do projeto de servidor, obtenha e aplique o segredo do cliente usando o seguinte código:
var tenantId = builder.Configuration.GetValue<string>("AzureAd:TenantId")!;
var vaultUri = builder.Configuration.GetValue<string>("AzureAd:VaultUri")!;
var secretName = builder.Configuration.GetValue<string>("AzureAd:SecretName")!;
builder.Services.Configure<MicrosoftIdentityOptions>(
OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
options.ClientSecret =
AzureHelper.GetKeyVaultSecret(tenantId, vaultUri, secretName);
});
Se você deseja controlar o ambiente onde o código anterior opera, por exemplo, para evitar executar o código localmente porque optou por usar a ferramenta Secret Manager para desenvolvimento local, você pode encapsular o código anterior em uma instrução condicional que verifica o ambiente:
if (!context.HostingEnvironment.IsDevelopment())
{
...
}
Na secção AzureAd
do appsettings.json
, adicione as seguintes chaves de configuração e valores VaultUri
e SecretName
:
"VaultUri": "{VAULT URI}",
"SecretName": "{SECRET NAME}"
No exemplo anterior:
- O marcador
{VAULT URI}
é o URI do cofre de chaves. Inclua a barra final ao URI. - O placeholder
{SECRET NAME}
é o nome secreto.
Exemplo:
"VaultUri": "https://contoso.vault.azure.net/",
"SecretName": "BlazorWebAppEntra"
A configuração é usada para facilitar o fornecimento de cofres de chaves dedicados e nomes secretos com base nos arquivos de configuração ambiental do aplicativo. Por exemplo, você pode fornecer valores de configuração diferentes para appsettings.Development.json
em desenvolvimento, appsettings.Staging.json
durante o preparo e appsettings.Production.json
para a implantação de produção. Para obter mais informações, consulte configuração do ASP.NET Core Blazor.
Redirecionar para a página inicial ao sair
O componente LogInOrOut
(Layout/LogInOrOut.razor
) define um campo oculto para o URL de retorno (ReturnUrl
) para o URL atual (currentURL
). Quando o usuário sai do aplicativo, o provedor de identidade retorna o usuário para a página da qual ele fez logout. Se o usuário fizer logout de uma página segura, ele será retornado à mesma página segura e enviado de volta através do processo de autenticação. Esse fluxo de autenticação é razoável quando os usuários precisam alterar contas regularmente.
Como alternativa, use o seguinte componente LogInOrOut
, que não fornece uma URL de retorno ao fazer logout.
Layout/LogInOrOut.razor
:
<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>
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 inferior no aplicativo de servidor.
Para habilitar o registo de depuração ou rastreamento para autenticação Blazor WebAssembly, consulte a seção Log de autenticação do lado do cliente na documentação de ASP.NET Core Blazor de registo, com o selecionador 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 endpoints da API da web do servidor.
- Executar a aplicação numa porta diferente daquela configurada no 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:
- Google Chrome (documentação do Google)
- Microsoft Edge
- Mozilla Firefox (documentação da Mozilla)
A equipa de documentação responde a comentários e sinais de erro nos artigos (abrir um problema na secção de comentários Esta página), mas não pode fornecer suporte de 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 e nem confidenciais, abra um problema com a equipa do 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] A autorização falhou. Estes requisitos não foram atendidos: DenyAnonymousAuthorizationRequirement: Requer um usuário autenticado.
Erro de retorno de 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:
- No portal do Azure, aceda ao manifesto do aplicativo .
- Defina o atributo
allowPublicClient
comonull
outrue
.
- Erro:
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 de início de 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
- Microsoft Edge:
- No campo Argumentos, forneça a opção de linha de comando que o navegador usa para abrir no modo InPrivate ou no modo incógnito. Alguns navegadores exigem o URL do aplicativo.
- Microsoft Edge: Use
-inprivate
. - Google Chrome: use o
--incognito --new-window {URL}
, onde o espaço reservado{URL}
é o URL a ser aberto (por exemplo,https://localhost:5001
). - Mozilla Firefox: Use
-private -url {URL}
, onde o espaço reservado{URL}
é o URL a ser aberto (por exemplo,https://localhost:5001
).
- Microsoft Edge: Use
- Forneça um nome no campo Nome amigável. Por exemplo,
Firefox Auth Testing
. - Selecione o botão OK.
- Para evitar ter que 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 predefinido.
- 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:
- Limpe os caches de pacotes NuGet do sistema local executando
dotnet nuget locals all --clear
a partir de um shell de comando. - Exclua as pastas
bin
eobj
do projeto. - Restaure e reconstrua o projeto.
- 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 Explorador de Pacotes FuGet .
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
- Documentação da plataforma de identidade da Microsoft
-
AzureAD/microsoft-identity-web
repositório GitHub: Orientações úteis sobre a implementação do Microsoft Identity Web para Microsoft Entra ID e Azure Ative Directory B2C para aplicativos ASP.NET Core, incluindo links para aplicativos de exemplo e documentação relacionada do Azure. Atualmente, Blazor Web Apps não são explicitamente abordadas pela documentação do Azure, mas a instalação e configuração de um Blazor Web App para ME-ID e para hospedagem em Azure é a mesma que para qualquer aplicação web ASP.NET Core. -
AuthenticationStateProvider
serviço - Gerenciar o estado de autenticação no do Blazor Web App
- Abstrações de serviço em Blazor Web App