Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.
Advertência
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.
ASP.NET Core Identity fornece APIs que lidam com autenticação, autorização e gerenciamento de identidade. As APIs permitem assegurar os terminais de um back-end de API Web com autenticação baseada em cookie. Uma opção baseada em tokens está disponível para clientes que não podem usar cookies, mas ao usá-la você é responsável por garantir que os tokens sejam mantidos seguros. Recomendamos o uso de cookies para aplicativos baseados em navegador, porque, por padrão, o navegador os manipula automaticamente sem expô-los ao JavaScript.
Este artigo mostra como usar o Identity para proteger um back-end de API da Web para SPAs como aplicativos Angular, React e Vue. As mesmas APIs de back-end podem ser usadas para proteger aplicativos Blazor WebAssembly.
Pré-requisitos
As etapas mostradas neste artigo adicionam autenticação e autorização a um aplicativo ASP.NET Core Web API que:
- Ainda não está configurado para autenticação.
- Alvos
net8.0ou posteriores. - Pode ser API mínima ou API baseada em controlador.
Algumas das instruções de teste neste artigo usam a interface Swagger UI incluída no template de projeto. A Interface de Usuário do Swagger não é necessária para usar Identity com um back-end de API Web.
Instalar pacotes NuGet
Instale os seguintes pacotes NuGet:
-
Microsoft.AspNetCore.Identity.EntityFrameworkCore- Permite que Identity trabalhem com o Entity Framework Core (EF Core). - Um que permite que EF Core trabalhem com um banco de dados, como um dos seguintes pacotes:
Para obter a maneira mais rápida de começar, use o banco de dados na memória.
Altere o banco de dados posteriormente para SQLite ou SQL Server para salvar dados do usuário entre sessões durante o teste ou para uso em produção. Isso introduz alguma complexidade em comparação com o armazenamento em memória, pois requer que o banco de dados seja criado por meio de migrações , como mostrado no tutorial de introdução EF Core.
Instale esses pacotes usando o gerenciador de pacotes NuGet no Visual Studio ou o comando dotnet add package CLI.
Criar um IdentityDbContext
Adicione uma classe chamada ApplicationDbContext que herda de IdentityDbContext<TUser>:
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :
base(options)
{ }
}
O código mostrado fornece um construtor especial que torna possível configurar o banco de dados para diferentes ambientes.
Adicione uma ou mais das seguintes diretivas using, conforme necessário, ao adicionar o código mostrado nestas etapas.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
Configurar o contexto EF Core
Como observado anteriormente, a maneira mais simples de começar é usar o banco de dados na memória. Com in-memory, cada execução começa com um novo banco de dados e não há necessidade de usar migrações. Após a chamada para WebApplication.CreateBuilder(args), adicione o seguinte código para configurar Identity para usar um banco de dados na memória:
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseInMemoryDatabase("AppDb"));
Para salvar dados do usuário entre sessões durante o teste ou para uso em produção, altere o banco de dados posteriormente para SQLite ou SQL Server.
Adicionar Identity serviços ao contêiner
Após a chamada para WebApplication.CreateBuilder(args), chame AddAuthorization para adicionar serviços ao contentor de injeção de dependência (DI):
builder.Services.AddAuthorization();
Ativar Identity APIs
Após a chamada para WebApplication.CreateBuilder(args), ligue para AddIdentityApiEndpoints<TUser>(IServiceCollection) e AddEntityFrameworkStores<TContext>(IdentityBuilder).
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Por padrão, tanto os cookies quanto os tokens proprietários são ativados. Cookies e tokens são emitidos no login se o parâmetro de cadeia de caracteres de consulta useCookies no ponto de extremidade de login for true.
Rotas do Mapa Identity
Após a chamada de builder.Build(), chame MapIdentityApi<TUser>(IEndpointRouteBuilder) para mapear os Identity terminais.
app.MapIdentityApi<IdentityUser>();
Proteger os pontos finais selecionados
Para proteger um endereço final, use o método de extensão RequireAuthorization durante a chamada de Map{Method} que define a rota. Por exemplo:
app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
})
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization();
O método RequireAuthorization também pode ser usado para:
Proteger os endpoints da interface do Swagger, conforme mostrado no exemplo a seguir:
app.MapSwagger().RequireAuthorization();Proteja-se com uma declaração ou permissão específica, conforme mostrado no exemplo a seguir:
.RequireAuthorization("Admin");
Em um projeto de API da Web baseado em controlador, proteja os pontos de extremidade aplicando o atributo [Authorize] a um controlador ou a uma ação.
Testar a API
Uma maneira rápida de testar a autenticação é usar o banco de dados na memória e a interface do usuário do Swagger incluída no modelo de projeto. As etapas a seguir mostram como testar a API com a interface do usuário do Swagger. Certifique-se de que os endpoints da IU do Swagger não estejam protegidos.
Tentar aceder a um endpoint seguro
- Execute o aplicativo e navegue até a interface do usuário do Swagger.
- Expanda um endpoint seguro, como
/weatherforecast, num projeto criado pelo modelo de API web. - Selecione Experimente.
- Selecione Executar. A resposta é
401 - not authorized.
Inscrição no teste
Expanda
/registere selecione Experimente.Na seção Parâmetros da interface do utilizador, um corpo de solicitação de exemplo é mostrado:
{ "email": "string", "password": "string" }Substitua "string" por um endereço de e-mail e senha válidos e selecione Executar.
Para estar em conformidade com as regras de validação de senha padrão, a senha deve ter pelo menos seis caracteres e conter pelo menos um de cada um dos seguintes caracteres:
- Letra maiúscula
- Letra minúscula
- Dígito numérico
- Caractere não alfanumérico
Se você inserir um endereço de e-mail inválido ou uma senha incorreta, o resultado incluirá os erros de validação. Aqui está um exemplo de um corpo de resposta com erros de validação:
{ "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1", "title": "One or more validation errors occurred.", "status": 400, "errors": { "PasswordTooShort": [ "Passwords must be at least 6 characters." ], "PasswordRequiresNonAlphanumeric": [ "Passwords must have at least one non alphanumeric character." ], "PasswordRequiresDigit": [ "Passwords must have at least one digit ('0'-'9')." ], "PasswordRequiresLower": [ "Passwords must have at least one lowercase ('a'-'z')." ] } }Os erros são retornados no formato ProblemDetails para que o cliente possa analisá-los e exibir erros de validação, conforme necessário.
Um registo bem-sucedido resulta numa resposta
200 - OK.
Teste de login
Expanda
/logine selecione Experimente. O corpo da solicitação de exemplo mostra dois parâmetros adicionais:{ "email": "string", "password": "string", "twoFactorCode": "string", "twoFactorRecoveryCode": "string" }As propriedades JSON extras não são necessárias para este exemplo e podem ser excluídas. Defina
useCookiesparatrue.Substitua "string" pelo endereço de e-mail e senha que você usou para se registrar e, em seguida, selecione Executar.
Um login bem-sucedido resulta em uma resposta
200 - OKcom um cookie no cabeçalho da resposta.
Teste novamente o ponto de extremidade seguro
Após um login bem-sucedido, reexecute o endpoint seguro. A autenticação cookie é enviada automaticamente com a solicitação, e a interface é autorizada. A autenticação baseada em Cookieé incorporada com segurança ao navegador e "simplesmente funciona".
Testar com clientes não baseados em navegador
Alguns clientes da Web podem não incluir cookies no cabeçalho por padrão:
Se estiver a utilizar uma ferramenta para testar APIs, poderá ter de ativar os cookies nas definições.
A API de
fetchJavaScript não inclui cookies por padrão. Habilite-os definindocredentialspara o valorincludenas opções.Um
HttpClientem execução em um aplicativo Blazor WebAssembly precisa doHttpRequestMessagepara incluir credenciais, como o exemplo a seguir:request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
Usar autenticação baseada em token
Recomendamos o uso de cookies em aplicativos baseados em navegadores, porque, por padrão, o navegador os manipula automaticamente sem expô-los ao JavaScript.
É emitido um token personalizado (proprietário da plataforma de identidade ASP.NET Core) que pode ser usado para autenticar solicitações subsequentes. O token é passado no cabeçalho Authorization como um token portador. Um token de atualização também é fornecido. Esse token permite que o aplicativo solicite um novo token quando o antigo expirar sem forçar o usuário a fazer login novamente.
Os tokens não são JSON Web Tokens (JWTs) padrão. O uso de tokens personalizados é intencional, pois a API de Identity interna destina-se principalmente a cenários simples. A opção de token não se destina a ser um provedor de serviços de identidade completo ou servidor de token, mas sim uma alternativa à opção cookie para clientes que não podem usar cookies.
Para usar a autenticação baseada em token, defina o parâmetro de cadeia de caracteres de consulta useCookies como false ao chamar o ponto de extremidade /login. Os tokens usam o esquema de autenticação por portador . Usando o token retornado da chamada para /login, as chamadas subsequentes para pontos de extremidade protegidos devem adicionar o cabeçalho Authorization: Bearer <token> onde <token> é o token de acesso. Para mais informações, veja utilizer o endpoint POST /login mais adiante neste artigo.
Terminar sessão
Para fornecer uma forma de o utilizador terminar sessão, defina um ponto de extremidade /logout como no exemplo a seguir:
app.MapPost("/logout", async (SignInManager<IdentityUser> signInManager,
[FromBody] object empty) =>
{
if (empty != null)
{
await signInManager.SignOutAsync();
return Results.Ok();
}
return Results.Unauthorized();
})
.WithOpenApi()
.RequireAuthorization();
Forneça um objeto JSON vazio ({}) no corpo da solicitação ao chamar esse ponto de extremidade. O código a seguir é um exemplo de uma chamada para o endpoint de logout.
public signOut() {
return this.http.post('/logout', {}, {
withCredentials: true,
observe: 'response',
responseType: 'text'
Os MapIdentityApi<TUser> pontos finais
A chamada para MapIdentityApi<TUser> adiciona os seguintes pontos de extremidade à aplicação:
POST /registerPOST /loginPOST /refreshGET /confirmEmailPOST /resendConfirmationEmailPOST /forgotPasswordPOST /resetPasswordPOST /manage/2faGET /manage/infoPOST /manage/info
Use o ponto de extremidade POST /register
O corpo do pedido deve ter as propriedades Email e Password.
{
"email": "string",
"password": "string",
}
Para mais informações, consulte:
- Registo de teste anteriormente neste artigo.
- RegisterRequest.
Use o ponto de extremidade POST /login
Os dados Email e Password são obrigatórios no corpo do pedido. Se a autenticação de dois fatores (2FA) estiver habilitada, será necessário TwoFactorCode ou TwoFactorRecoveryCode. Se o 2FA não estiver habilitado, omita twoFactorCode e twoFactorRecoveryCode. Para mais informações, veja utilizer o endpoint POST /manage/2fa mais adiante neste artigo.
Aqui está um exemplo de corpo de solicitação com 2FA não habilitado:
{
"email": "string",
"password": "string"
}
Aqui estão exemplos de corpo de solicitação com 2FA habilitado:
-
{ "email": "string", "password": "string", "twoFactorCode": "string", } -
{ "email": "string", "password": "string", "twoFactorRecoveryCode": "string" }
O ponto de extremidade espera um parâmetro de cadeia de consulta:
-
useCookies- Defina comotruepara autenticação baseada em cookie. Defina comofalseou omitir para autenticação baseada em token.
Para obter mais informações acerca da autenticação baseada em cookie, consulte a seção Teste de login na seção anterior deste artigo.
Autenticação baseada em tokens
Se useCookies é false ou omitido, a autenticação baseada em tokens é habilitada. O corpo da resposta inclui as seguintes propriedades:
{
"tokenType": "string",
"accessToken": "string",
"expiresIn": 0,
"refreshToken": "string"
}
Para obter mais informações sobre essas propriedades, consulte AccessTokenResponse.
Coloque o token de acesso em um cabeçalho para fazer solicitações autenticadas, conforme mostrado no exemplo a seguir
Authorization: Bearer {access token}
Quando o token de acesso estiver prestes a expirar, chame o endpoint /refresh.
Use o ponto de extremidade POST /refresh
Para uso somente com autenticação baseada em token. Obtém um novo token de acesso sem forçar o usuário a fazer login novamente. Chame este endpoint quando o token de acesso estiver prestes a expirar.
O corpo da solicitação contém apenas o RefreshToken. Aqui está um exemplo de corpo de solicitação:
{
"refreshToken": "string"
}
Se a chamada for bem-sucedida, o corpo da resposta será um novo AccessTokenResponse, conforme mostrado no exemplo a seguir:
{
"tokenType": "string",
"accessToken": "string",
"expiresIn": 0,
"refreshToken": "string"
}
Use o ponto de extremidade GET /confirmEmail
Se Identity estiver configurado para confirmação de email, uma chamada bem-sucedida para o ponto de extremidade /register enviará um e-mail contendo um link para o ponto de extremidade /confirmEmail. O link contém os seguintes parâmetros de cadeia de caracteres de consulta:
userIdcode-
changedEmail- Incluído apenas se o utilizador alterou o endereço de e-mail durante o registo.
Identity fornece texto padrão para o e-mail de confirmação. Por padrão, o assunto do e-mail é "Confirmar seu e-mail" e o corpo do e-mail se parece com o exemplo a seguir:
Please confirm your account by <a href='https://contoso.com/confirmEmail?userId={user ID}&code={generated code}&changedEmail={new email address}'>clicking here</a>.
Se a propriedade RequireConfirmedEmail estiver definida como true, o usuário não poderá fazer login até que o endereço de e-mail seja confirmado clicando no link no e-mail. O ponto de extremidade /confirmEmail:
- Confirma o endereço de e-mail e permite que o usuário faça login.
- Devolve o texto "Obrigado por confirmar o seu e-mail." no corpo da resposta.
Para configurar Identity para confirmação de e-mail, adicione código em Program.cs definir RequireConfirmedEmail para true e adicione uma classe que implemente IEmailSender ao contêiner DI. Por exemplo:
builder.Services.Configure<IdentityOptions>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
});
builder.Services.AddTransient<IEmailSender, EmailSender>();
Para obter mais informações, consulte Confirmação de conta e recuperação de senha no ASP.NET Core.
Identity fornece texto padrão para os outros e-mails que também precisam ser enviados, como para 2FA e redefinição de senha. Para personalizar esses e-mails, forneça uma implementação personalizada da interface IEmailSender. No exemplo anterior, EmailSender é uma classe que implementa IEmailSender. Para obter mais informações, incluindo um exemplo de uma classe que implementa IEmailSender, consulte Confirmação de conta e recuperação de senha no ASP.NET Core.
Use o ponto de extremidade POST /resendConfirmationEmail
Envia um e-mail somente se o endereço for válido para um usuário registrado.
O corpo da solicitação contém apenas o Email. Aqui está um exemplo de corpo de solicitação:
{
"email": "string"
}
Para obter mais informações, veja Uso do ponto de extremidade GET /confirmEmail anteriormente neste artigo.
Use o ponto de extremidade POST /forgotPassword
Gera um e-mail que contém um código de redefinição de senha. Envie esse código para /resetPassword com uma nova senha.
O corpo da solicitação contém apenas o Email. Aqui está um exemplo:
{
"email": "string"
}
Para obter informações sobre como ativar Identity para enviar endereços de e-mail, consulte Utilizar o ponto final GET /confirmEmail.
Use o ponto de extremidade POST /resetPassword
Chame este endpoint depois de obter um código de redefinição chamando o endpoint /forgotPassword.
O corpo da solicitação requer Email, ResetCodee NewPassword. Aqui está um exemplo:
{
"email": "string",
"resetCode": "string",
"newPassword": "string"
}
Use o ponto de extremidade POST /manage/2fa
Configura a autenticação de dois fatores (2FA) para o usuário. Quando o 2FA está ativado, o login bem-sucedido requer um código produzido por um aplicativo autenticador, além do endereço de e-mail e senha.
Ativar 2FA
Para habilitar o 2FA para o usuário autenticado no momento:
Chame o endpoint
/manage/2fa, enviando um objeto JSON vazio ({}) no corpo da solicitação.O corpo da resposta fornece o SharedKey juntamente com algumas outras propriedades que não são necessárias neste momento. A chave compartilhada é usada para configurar o aplicativo autenticador. Exemplo de corpo de resposta:
{ "sharedKey": "string", "recoveryCodesLeft": 0, "recoveryCodes": null, "isTwoFactorEnabled": false, "isMachineRemembered": false }Utilize a chave partilhada para obter uma palavra-passe temporária baseada no tempo (TOTP). Para obter mais informações, consulte Habilitar a geração de código QR para aplicativos autenticadores TOTP no ASP.NET Core.
Contacte o ponto de extremidade
/manage/2fa, enviando o TOTP e"enable": trueno corpo da solicitação. Por exemplo:{ "enable": true, "twoFactorCode": "string" }O corpo de resposta confirma que IsTwoFactorEnabled é verdade e fornece RecoveryCodes. Os códigos de recuperação são usados para fazer login quando o aplicativo autenticador não está disponível. Exemplo de corpo de resposta depois de ativar com êxito o 2FA:
{ "sharedKey": "string", "recoveryCodesLeft": 10, "recoveryCodes": [ "string", "string", "string", "string", "string", "string", "string", "string", "string", "string" ], "isTwoFactorEnabled": true, "isMachineRemembered": false }
Faça login com 2FA
Chame o ponto final /login, enviando o endereço de e-mail, a palavra-passe e o TOTP no corpo da solicitação. Por exemplo:
{
"email": "string",
"password": "string",
"twoFactorCode": "string"
}
Se o usuário não tiver acesso ao aplicativo autenticador, faça login chamando o ponto de extremidade /login com um dos códigos de recuperação fornecidos quando o 2FA foi habilitado. O corpo da solicitação se parece com o exemplo a seguir:
{
"email": "string",
"password": "string",
"twoFactorRecoveryCode": "string"
}
Redefinir os códigos de recuperação
Para obter um novo conjunto de códigos de recuperação, utilize este endpoint com ResetRecoveryCodes definido como true. Aqui está um exemplo de corpo de solicitação:
{
"resetRecoveryCodes": true
}
Redefinir a chave compartilhada
Para obter uma nova chave partilhada aleatória, utilize este endpoint com ResetSharedKey configurado para true. Aqui está um exemplo de corpo de solicitação:
{
"resetSharedKey": true
}
A redefinição da chave desativa automaticamente o requisito de login de dois fatores para o usuário autenticado até que ele seja reativado por uma solicitação posterior.
Esqueça a máquina
Para limpar o cookie sinalizador "lembrar de mim", se presente, chame este endpoint com ForgetMachine definido como true. Aqui está um exemplo de corpo de solicitação:
{
"forgetMachine": true
}
Este endpoint não tem impacto na autenticação baseada em token.
Use o ponto de extremidade GET /manage/info
Obtém o endereço de e-mail e o status de confirmação de e-mail do usuário conectado. Foram omitidas declarações desta interface por motivos de segurança. Se as reivindicações forem necessárias, use as APIs no servidor para configurar um endpoint para reivindicações. Ou, em vez de compartilhar todas as declarações dos usuários, forneça um ponto de extremidade de validação que aceite uma declaração e responda se o usuário a tem.
A solicitação não requer parâmetros. O corpo da resposta inclui as propriedades Email e IsEmailConfirmed, como no exemplo a seguir:
{
"email": "string",
"isEmailConfirmed": true
}
Use o ponto de extremidade POST /manage/info
Atualiza o endereço de e-mail e a senha do usuário conectado. Envie NewEmail, NewPassworde OldPassword no corpo da solicitação, conforme mostrado no exemplo a seguir:
{
"newEmail": "string",
"newPassword": "string",
"oldPassword": "string"
}
Aqui está um exemplo do corpo da resposta:
{
"email": "string",
"isEmailConfirmed": false
}
Ver também
Para obter mais informações, consulte os seguintes recursos:
- Escolha uma solução de gerenciamento de identidades
- Soluções de gestão para aplicativos web .NET
- Autorização simples no ASP.NET Core
- Adicionar, baixar e excluir dados do usuário para Identity em um projeto ASP.NET Core
- Criar um aplicativo ASP.NET Core com dados do usuário protegidos por autorização
- Confirmação de conta e recuperação de senha no ASP.NET Core
- Habilite a geração de código QR para aplicativos autenticadores TOTP no ASP.NET Core
-
Exemplo de back-end de API Web para SPAs O arquivo .http mostra a autenticação baseada em token. Por exemplo:
- Não define
useCookies - Usa o cabeçalho Authorization para passar o token
- Mostra a atualização para estender a sessão sem forçar o usuário a fazer login novamente
- Não define
- aplicativo Angular de exemplo que usa Identity para proteger um back-end de API Web
Os modelos ASP.NET Core oferecem autenticação em SPAs (Single Page Apps) usando o suporte para autorização de API. ASP.NET Core Identity para autenticação e armazenamento de utilizadores é combinado com Duende Identity Server para implementar o OpenID Connect.
Importante
Duende Software pode exigir que você pague uma taxa de licença para uso de produção do Duende Identity Server. Para obter mais informações, consulte Migrar do ASP.NET Core no .NET 5 para o .NET 6.
Um parâmetro de autenticação foi adicionado aos modelos de projeto Angular e React que é semelhante ao parâmetro de autenticação nos modelos de projeto Web Application (Model-View-Controller) (MVC) e Web Application (Razor Pages). Os valores de parâmetros permitidos são Nenhum e Individual. O modelo de projeto React.js e Redux não suporta o parâmetro de autenticação no momento.
Criar um aplicativo com suporte de autorização de API
A autenticação e autorização do usuário podem ser usadas com SPAs Angular e React. Abra um shell de comando e execute o seguinte comando:
Angular:
dotnet new angular -au Individual
Reagir:
dotnet new react -au Individual
O comando anterior cria um aplicativo ASP.NET Core com um diretório ClientApp que contém o SPA.
Descrição geral dos componentes do ASP.NET Core da aplicação
As seções a seguir descrevem adições ao projeto quando o suporte à autenticação está incluído:
Program.cs
Os exemplos de código a seguir dependem do pacote Microsoft.AspNetCore.ApiAuthorization.IdentityServer NuGet. Os exemplos configuram autenticação e autorização de API usando os métodos de extensão AddApiAuthorization e AddIdentityServerJwt. Os projetos que usam os modelos de projeto React ou Angular SPA com autenticação incluem uma referência a este pacote.
dotnet new angular -au Individual gera o seguinte arquivo Program.cs:
using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using output_directory_name.Data;
using output_directory_name.Models;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapFallbackToFile("index.html");
app.Run();
O código anterior configura:
Identity com a interface do usuário padrão:
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite(connectionString)); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();IdentityServer com um método auxiliar de
AddApiAuthorizationadicional que configura algumas convenções padrão do ASP.NET Core sobre o IdentityServer:builder.Services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();Autenticação com um método auxiliar de
AddIdentityServerJwtadicional que configura o aplicativo para validar tokens JWT produzidos por IdentityServer:builder.Services.AddAuthentication() .AddIdentityServerJwt();O middleware de autenticação responsável por validar as credenciais da solicitação e definir o usuário no contexto da solicitação:
app.UseAuthentication();O middleware do IdentityServer que expõe os endpoints do OpenID Connect:
app.UseIdentityServer();
Advertência
Este artigo mostra o uso de cadeias de conexão. Com um banco de dados local, o usuário não precisa ser autenticado, mas na produção, as cadeias de conexão às vezes incluem uma senha para autenticar. Uma credencial de senha de proprietário de recurso (ROPC) é um risco de segurança que deve ser evitado em bancos de dados de produção. Os aplicativos de produção devem usar o fluxo de autenticação mais seguro disponível. Para obter mais informações sobre autenticação para aplicativos implantados em ambientes de teste ou produção, consulte Fluxos de autenticação segura.
Serviço de Aplicações do Azure no Linux
Para implantações do Serviço de Aplicativo do Azure no Linux, especifique o emissor explicitamente:
builder.Services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
options.Authority = "{AUTHORITY}";
});
No código anterior, o espaço reservado para {AUTHORITY} é o Authority a ser usado quando se fazem chamadas OpenID Connect.
Exemplo:
options.Authority = "https://contoso-service.azurewebsites.net";
AddApiAuthorization
Este método auxiliar configura o IdentityServer para usar nossa configuração suportada. O IdentityServer é uma estrutura poderosa e extensível para lidar com questões de segurança de aplicativos. Ao mesmo tempo, isso expõe uma complexidade desnecessária para os cenários mais comuns. Consequentemente, um conjunto de convenções e opções de configuração é fornecido a você que são considerados um bom ponto de partida. Depois que suas necessidades de autenticação mudarem, todo o poder do IdentityServer ainda estará disponível para personalizar a autenticação de acordo com suas necessidades.
AddIdentityServerJwt
Esse método auxiliar configura um esquema de política para o aplicativo como o manipulador de autenticação padrão. A política está configurada para permitir que Identity manipule todas as solicitações encaminhadas para qualquer subcaminho no espaço de URLs Identity "/Identity". O JwtBearerHandler lida com todas as outras solicitações. Além disso, esse método registra um recurso de API <<ApplicationName>>API com IdentityServer com um escopo padrão de <<ApplicationName>>API e configura o middleware de token JWT Bearer para validar tokens emitidos pelo IdentityServer para o aplicativo.
WeatherForecastController
No arquivo, observe o atributo [Authorize] aplicado à classe que indica que o usuário precisa ser autorizado com base na política padrão para acessar o recurso. A política de autorização padrão passa a ser configurada para usar o esquema de autenticação padrão, que é configurado por AddIdentityServerJwt ao esquema de política mencionado acima, tornando o JwtBearerHandler configurado por esse método auxiliar o manipulador padrão para solicitações ao aplicativo.
ApplicationDbContext
No arquivo, observe que o mesmo DbContext é usado em Identity com a exceção de que ele estende ApiAuthorizationDbContext (uma classe mais derivada de IdentityDbContext) para incluir o esquema para IdentityServer.
Para obter controle total do esquema de banco de dados, herde de uma das classes de IdentityDbContext disponíveis e configure o contexto para incluir o esquema Identity chamando builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) no método OnModelCreating.
OidcConfigurationController
No arquivo, repare no endpoint que é configurado para fornecer os parâmetros OIDC que o cliente precisa usar.
appsettings.json
No arquivo appsettings.json da raiz do projeto, há uma nova seção de IdentityServer que descreve a lista de clientes configurados. No exemplo a seguir, há um único cliente. O nome do cliente corresponde ao nome do aplicativo e é mapeado por convenção para o parâmetro OAuth ClientId. O perfil indica o tipo de aplicativo que está sendo configurado. Ele é usado internamente para conduzir convenções que simplificam o processo de configuração para o servidor. Existem vários perfis disponíveis, conforme explicado na seção Perfis de aplicativos.
"IdentityServer": {
"Clients": {
"angularindividualpreview3final": {
"Profile": "IdentityServerSPA"
}
}
}
appsettings.Development.json
No arquivo appsettings.Development.json da raiz do projeto, há uma seção IdentityServer que descreve a chave usada para assinar tokens. Ao implantar na produção, uma chave precisa ser provisionada e implantada junto com o aplicativo, conforme explicado na seção Implantar na produção.
"IdentityServer": {
"Key": {
"Type": "Development"
}
}
Descrição geral da aplicação Angular
O suporte à autenticação e autorização de API no modelo Angular reside em seu próprio módulo Angular no diretório ClientApp/src/api-authorization. O módulo é composto pelos seguintes elementos:
- 3 componentes:
-
login.component.ts: Manipula o fluxo de login do aplicativo. -
logout.component.ts: Manipula o fluxo de logout do aplicativo. -
login-menu.component.ts: Um widget que exibe um dos seguintes conjuntos de links:- Gerenciamento de perfil de usuário e links de logout quando o usuário é autenticado.
- Links de registro e login quando o usuário não está autenticado.
-
- Uma proteção de rota
AuthorizeGuardque pode ser adicionada às rotas e exige que um usuário seja autenticado antes de visitar a rota. - Um intercetador HTTP
AuthorizeInterceptorque anexa o token de acesso a solicitações HTTP de saída direcionadas à API quando o usuário é autenticado. - Um serviço
AuthorizeServiceque lida com os detalhes de nível inferior do processo de autenticação e expõe informações sobre o usuário autenticado ao restante do aplicativo para consumo. - Um módulo Angular que define rotas associadas às partes de autenticação do aplicativo. Ele expõe o componente de menu de login, o intercetador, a salvaguarda e o serviço para ser utilizado pelo resto da aplicação.
Descrição geral da aplicação React
O suporte para autenticação e autorização de API no modelo React reside no diretório ClientApp/src/components/api-authorization. É composto pelos seguintes elementos:
- 4 componentes:
-
Login.js: Manipula o fluxo de login do aplicativo. -
Logout.js: Manipula o fluxo de logout do aplicativo. -
LoginMenu.js: Um widget que exibe um dos seguintes conjuntos de links:- Gerenciamento de perfil de usuário e links de logout quando o usuário é autenticado.
- Links de registro e login quando o usuário não está autenticado.
-
AuthorizeRoute.js: Um componente de rota que requer que um usuário seja autenticado antes de renderizar o componente indicado no parâmetroComponent.
-
- Uma instância
authServiceexportada de classeAuthorizeServiceque lida com os detalhes de nível inferior do processo de autenticação e expõe informações sobre o usuário autenticado ao restante do aplicativo para consumo.
Agora que você já viu os principais componentes da solução, você pode dar uma olhada mais profunda em cenários individuais para o aplicativo.
Exigir autorização em uma nova API
Por padrão, o sistema é configurado para exigir facilmente autorização para novas APIs. Para fazer isso, crie um novo controlador e adicione o atributo [Authorize] à classe controller ou a qualquer ação dentro do controller.
Personalizar o manipulador de autenticação de API
Para personalizar a configuração do manipulador JWT da API, configure sua JwtBearerOptions instância:
builder.Services.AddAuthentication()
.AddIdentityServerJwt();
builder.Services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
...
});
O manipulador JWT da API gera eventos que permitem o controle sobre o processo de autenticação usando JwtBearerEvents. Para fornecer suporte para autorização de API, AddIdentityServerJwt registra seus próprios manipuladores de eventos.
Para personalizar a manipulação de um evento, envolva o manipulador de eventos existente com lógica adicional, conforme necessário. Por exemplo:
builder.Services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
var onTokenValidated = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await onTokenValidated(context);
...
}
});
No código anterior, o manipulador de eventos OnTokenValidated é substituído por uma implementação personalizada. Esta implementação:
- Chama a implementação original fornecida pelo suporte de autorização da API.
- Execute sua própria lógica personalizada.
Proteger uma rota do lado do cliente (Angular)
A proteção de uma rota do lado do cliente é feita adicionando a salvaguarda de autorização à lista de salvaguardas a serem executadas ao configurar uma rota. Como exemplo, você pode ver como a rota fetch-data está configurada no módulo Angular do aplicativo principal:
RouterModule.forRoot([
// ...
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])
É importante mencionar que proteger uma rota não protege o ponto de extremidade real (que ainda requer um atributo [Authorize] aplicado a ele), mas que só impede que o usuário navegue para a rota do lado do cliente quando ela não é autenticada.
Autenticar solicitações de API (Angular)
A autenticação de solicitações em APIs hospedadas ao lado do aplicativo é feita automaticamente por meio do uso do intercetador de cliente HTTP definido pelo aplicativo.
Proteger uma rota do lado do cliente (React)
Proteja uma rota do lado do cliente usando o componente AuthorizeRoute em vez do componente Route simples. Por exemplo, observe como a rota fetch-data é configurada dentro do componente App:
<AuthorizeRoute path='/fetch-data' component={FetchData} />
Proteger uma rota:
- Não protege o ponto de extremidade real (que ainda requer um atributo
[Authorize]aplicado a ele). - Só impede que o usuário navegue até a rota do lado do cliente quando ela não estiver autenticada.
Autenticar solicitações de API (React)
A autenticação de solicitações com o React é feita importando primeiro a instância authService do AuthorizeService. O token de acesso é recuperado do authService e é anexado à solicitação, conforme mostrado abaixo. Nos componentes do React, esse trabalho geralmente é feito no método de ciclo de vida do componentDidMount ou como resultado de alguma interação do usuário.
Importar o authService para um componente
import authService from './api-authorization/AuthorizeService'
Recuperar e anexar o token de acesso à resposta
async populateWeatherData() {
const token = await authService.getAccessToken();
const response = await fetch('api/SampleData/WeatherForecasts', {
headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
Implantar na produção
Para implantar o aplicativo na produção, os seguintes recursos precisam ser provisionados:
- Um banco de dados para armazenar as contas de usuário Identity e as concessões do IdentityServer.
- Um certificado de produção para usar na assinatura de tokens.
- Não existem requisitos específicos para este certificado; pode ser um certificado autoassinado ou um certificado provisionado por meio de uma autoridade de certificação.
- Ele pode ser gerado através de ferramentas padrão como PowerShell ou OpenSSL.
- O certificado pode ser instalado na loja de certificados das máquinas de destino ou implantado como um arquivo .pfx com uma senha forte.
Exemplo: Implantar em um provedor de hospedagem na Web que não seja do Azure
No seu painel de alojamento web, crie ou carregue o seu certificado. Em seguida, no arquivo appsettings.json do aplicativo, modifique a seção IdentityServer para incluir os principais detalhes. Por exemplo:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "WebHosting",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
No exemplo anterior:
-
StoreNamerepresenta o nome do armazenamento de certificados onde o certificado está armazenado. Neste caso, aponta para a loja de alojamento web. -
StoreLocationrepresenta de onde carregar o certificado (CurrentUserneste caso). -
Namecorresponde ao assunto distinguido para o certificado.
Exemplo: Implantar no Serviço de Aplicativo do Azure
Esta seção descreve a implantação do aplicativo no Serviço de Aplicativo do Azure usando um certificado armazenado no repositório de certificados. Para modificar o aplicativo para carregar um certificado do repositório de certificados, um plano de serviço de camada Standard ou superior é necessário quando você configura o aplicativo no portal do Azure em uma etapa posterior.
No arquivo appsettings.json do aplicativo, modifique a seção IdentityServer para incluir os principais detalhes:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "My",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
- O nome do repositório representa o nome do repositório de certificados onde o certificado está armazenado. Neste caso, ele aponta para a loja pessoal do utilizador.
- O local da loja representa onde se deve carregar o certificado (
CurrentUserouLocalMachine). - A propriedade nome no certificado corresponde ao sujeito distinto do certificado.
Para implantar a aplicação no Azure App Service, siga as etapas em Implantar a aplicação no Azure, que explicam como criar os recursos necessários do Azure e implantar a aplicação em produção.
Depois de seguir as instruções anteriores, o aplicativo é implantado no Azure, mas ainda não está funcional. O certificado usado pelo aplicativo deve ser configurado no portal do Azure. Encontre a impressão digital do certificado e siga as etapas descritas em Carregue os seus certificados.
Embora essas etapas mencionem SSL, há uma seção Certificados privados no portal do Azure onde você pode carregar o certificado provisionado para usar com o aplicativo.
Depois de definir o aplicativo e as configurações do aplicativo no portal do Azure, reinicie o aplicativo no portal.
Outras opções de configuração
O suporte para autorização de API se baseia no IdentityServer com um conjunto de convenções, valores padrão e aprimoramentos para simplificar a experiência de SPAs. Não é necessário dizer que todo o poder do IdentityServer está disponível nos bastidores, caso as integrações do ASP.NET Core não cubram o seu cenário. O suporte ASP.NET Core é focado em aplicativos "primários", onde todos os aplicativos são criados e implantados pela nossa organização. Como tal, não é oferecido suporte para aspetos como consentimento ou federação. Para esses cenários, use o IdentityServer e siga sua documentação.
Perfis de aplicação
Os perfis de aplicativo são configurações predefinidas para aplicativos que definem ainda mais seus parâmetros. Neste momento, os seguintes perfis são suportados:
-
IdentityServerSPA: Representa um SPA hospedado ao lado do IdentityServer como uma única unidade.- O
redirect_uriassume como padrão/authentication/login-callback. - O
post_logout_redirect_uriassume como padrão/authentication/logout-callback. - O conjunto de escopos inclui o
openid,profilee todos os escopos definidos para as APIs no aplicativo. - O conjunto de tipos de resposta OIDC permitidos é
id_token tokenou cada um deles individualmente (id_token,token). - O modo de resposta permitido é
fragment.
- O
-
SPA: Representa um SPA que não está hospedado com IdentityServer.- O conjunto de escopos inclui o
openid,profilee todos os escopos definidos para as APIs no aplicativo. - O conjunto de tipos de resposta OIDC permitidos é
id_token tokenou cada um deles individualmente (id_token,token). - O modo de resposta permitido é
fragment.
- O conjunto de escopos inclui o
-
IdentityServerJwt: Representa uma API hospedada junto com o IdentityServer.- O aplicativo está configurado para ter um único escopo que assume como padrão o nome do aplicativo.
-
API: Representa uma API que não está hospedada com o IdentityServer.- O aplicativo está configurado para ter um único escopo que assume como padrão o nome do aplicativo.
Configuração através do AppSettings
Configure as aplicações através do sistema de configuração, adicionando-as à lista de Clients ou Resources.
Configure a propriedade redirect_uri e post_logout_redirect_uri de cada cliente, conforme mostrado no exemplo a seguir:
"IdentityServer": {
"Clients": {
"MySPA": {
"Profile": "SPA",
"RedirectUri": "https://www.example.com/authentication/login-callback",
"LogoutUri": "https://www.example.com/authentication/logout-callback"
}
}
}
Ao configurar recursos, você pode configurar os escopos para o recurso conforme mostrado abaixo:
"IdentityServer": {
"Resources": {
"MyExternalApi": {
"Profile": "API",
"Scopes": "a b c"
}
}
}
Configuração através de código
Você também pode configurar os clientes e recursos por meio de código usando uma sobrecarga de AddApiAuthorization que executa uma ação para configurar opções.
AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddSPA(
"My SPA", spa =>
spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
.WithLogoutRedirectUri(
"http://www.example.com/authentication/logout-callback"));
options.ApiResources.AddApiResource("MyExternalApi", resource =>
resource.WithScopes("a", "b", "c"));
});
Recursos adicionais
Os modelos ASP.NET Core 3.1 ou posterior oferecem autenticação em SPAs (Single Page Apps) usando o suporte para autorização de API. ASP.NET Core Identity para autenticar e armazenar utilizadores é combinado com o IdentityServer para implementar o OpenID Connect.
Um parâmetro de autenticação foi adicionado aos modelos de projeto Angular e React que é semelhante ao parâmetro de autenticação nos modelos de projeto Web Application (Model-View-Controller) (MVC) e Web Application (Razor Pages). Os valores de parâmetros permitidos são Nenhum e Individual. O modelo de projeto React.js e Redux não suporta o parâmetro de autenticação no momento.
Criar um aplicativo com suporte de autorização de API
A autenticação e autorização do usuário podem ser usadas com SPAs Angular e React. Abra um shell de comando e execute o seguinte comando:
Angular:
dotnet new angular -o <output_directory_name>
Reagir:
dotnet new react -o <output_directory_name> -au Individual
O comando anterior cria um aplicativo ASP.NET Core com um diretório ClientApp que contém o SPA.
Descrição geral dos componentes do ASP.NET Core da aplicação
As seções a seguir descrevem adições ao projeto quando o suporte à autenticação está incluído:
Startup classe
Os exemplos de código a seguir dependem do pacote Microsoft.AspNetCore.ApiAuthorization.IdentityServer NuGet. Os exemplos configuram autenticação e autorização de API usando os métodos de extensão AddApiAuthorization e AddIdentityServerJwt. Os projetos que usam os modelos de projeto React ou Angular SPA com autenticação incluem uma referência a este pacote.
A classe Startup tem as seguintes adições:
Dentro do método
Startup.ConfigureServices:Identity com a interface do usuário padrão:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<ApplicationUser>() .AddEntityFrameworkStores<ApplicationDbContext>();IdentityServer com um método auxiliar de
AddApiAuthorizationadicional que configura algumas convenções padrão do ASP.NET Core sobre o IdentityServer:services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();Autenticação com um método auxiliar de
AddIdentityServerJwtadicional que configura o aplicativo para validar tokens JWT produzidos por IdentityServer:services.AddAuthentication() .AddIdentityServerJwt();
Dentro do método
Startup.Configure:O middleware de autenticação responsável por validar as credenciais da solicitação e definir o usuário no contexto da solicitação:
app.UseAuthentication();O middleware do IdentityServer que expõe os endpoints do OpenID Connect:
app.UseIdentityServer();
Advertência
Este artigo mostra o uso de cadeias de conexão. Com um banco de dados local, o usuário não precisa ser autenticado, mas na produção, as cadeias de conexão às vezes incluem uma senha para autenticar. Uma credencial de senha de proprietário de recurso (ROPC) é um risco de segurança que deve ser evitado em bancos de dados de produção. Os aplicativos de produção devem usar o fluxo de autenticação mais seguro disponível. Para obter mais informações sobre autenticação para aplicativos implantados em ambientes de teste ou produção, consulte Fluxos de autenticação segura.
Serviço de Aplicações do Azure no Linux
Para implantações do Serviço de Aplicativo do Azure no Linux, especifique o emissor explicitamente em Startup.ConfigureServices:
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
options.Authority = "{AUTHORITY}";
});
No código anterior, o espaço reservado para {AUTHORITY} é o Authority a ser usado quando se fazem chamadas OpenID Connect.
Exemplo:
options.Authority = "https://contoso-service.azurewebsites.net";
AddApiAuthorization
Este método auxiliar configura o IdentityServer para usar nossa configuração suportada. O IdentityServer é uma estrutura poderosa e extensível para lidar com questões de segurança de aplicativos. Ao mesmo tempo, isso expõe uma complexidade desnecessária para os cenários mais comuns. Consequentemente, um conjunto de convenções e opções de configuração é fornecido a você que são considerados um bom ponto de partida. Depois que suas necessidades de autenticação mudarem, todo o poder do IdentityServer ainda estará disponível para personalizar a autenticação de acordo com suas necessidades.
AddIdentityServerJwt
Esse método auxiliar configura um esquema de política para o aplicativo como o manipulador de autenticação padrão. A política está configurada para permitir que Identity manipule todas as solicitações encaminhadas para qualquer subcaminho no espaço de URLs Identity "/Identity". O JwtBearerHandler lida com todas as outras solicitações. Além disso, esse método registra um recurso de API <<ApplicationName>>API com IdentityServer com um escopo padrão de <<ApplicationName>>API e configura o middleware de token JWT Bearer para validar tokens emitidos pelo IdentityServer para o aplicativo.
WeatherForecastController
No arquivo, observe o atributo [Authorize] aplicado à classe que indica que o usuário precisa ser autorizado com base na política padrão para acessar o recurso. A política de autorização padrão passa a ser configurada para usar o esquema de autenticação padrão, que é configurado por AddIdentityServerJwt ao esquema de política mencionado acima, tornando o JwtBearerHandler configurado por esse método auxiliar o manipulador padrão para solicitações ao aplicativo.
ApplicationDbContext
No arquivo, observe que o mesmo DbContext é usado em Identity com a exceção de que ele estende ApiAuthorizationDbContext (uma classe mais derivada de IdentityDbContext) para incluir o esquema para IdentityServer.
Para obter controle total do esquema de banco de dados, herde de uma das classes de IdentityDbContext disponíveis e configure o contexto para incluir o esquema Identity chamando builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) no método OnModelCreating.
OidcConfigurationController
No arquivo, repare no endpoint que é configurado para fornecer os parâmetros OIDC que o cliente precisa usar.
appsettings.json
No arquivo appsettings.json da raiz do projeto, há uma nova seção de IdentityServer que descreve a lista de clientes configurados. No exemplo a seguir, há um único cliente. O nome do cliente corresponde ao nome do aplicativo e é mapeado por convenção para o parâmetro OAuth ClientId. O perfil indica o tipo de aplicativo que está sendo configurado. Ele é usado internamente para conduzir convenções que simplificam o processo de configuração para o servidor. Existem vários perfis disponíveis, conforme explicado na seção Perfis de aplicativos.
"IdentityServer": {
"Clients": {
"angularindividualpreview3final": {
"Profile": "IdentityServerSPA"
}
}
}
appsettings.Development.json
No arquivo appsettings.Development.json da raiz do projeto, há uma seção IdentityServer que descreve a chave usada para assinar tokens. Ao implantar na produção, uma chave precisa ser provisionada e implantada junto com o aplicativo, conforme explicado na seção Implantar na produção.
"IdentityServer": {
"Key": {
"Type": "Development"
}
}
Descrição geral da aplicação Angular
O suporte à autenticação e autorização de API no modelo Angular reside em seu próprio módulo Angular no diretório ClientApp/src/api-authorization. O módulo é composto pelos seguintes elementos:
- 3 componentes:
-
login.component.ts: Manipula o fluxo de login do aplicativo. -
logout.component.ts: Manipula o fluxo de logout do aplicativo. -
login-menu.component.ts: Um widget que exibe um dos seguintes conjuntos de links:- Gerenciamento de perfil de usuário e links de logout quando o usuário é autenticado.
- Links de registro e login quando o usuário não está autenticado.
-
- Uma proteção de rota
AuthorizeGuardque pode ser adicionada às rotas e exige que um usuário seja autenticado antes de visitar a rota. - Um intercetador HTTP
AuthorizeInterceptorque anexa o token de acesso a solicitações HTTP de saída direcionadas à API quando o usuário é autenticado. - Um serviço
AuthorizeServiceque lida com os detalhes de nível inferior do processo de autenticação e expõe informações sobre o usuário autenticado ao restante do aplicativo para consumo. - Um módulo Angular que define rotas associadas às partes de autenticação do aplicativo. Ele expõe o componente de menu de login, o intercetador, a salvaguarda e o serviço para ser utilizado pelo resto da aplicação.
Descrição geral da aplicação React
O suporte para autenticação e autorização de API no modelo React reside no diretório ClientApp/src/components/api-authorization. É composto pelos seguintes elementos:
- 4 componentes:
-
Login.js: Manipula o fluxo de login do aplicativo. -
Logout.js: Manipula o fluxo de logout do aplicativo. -
LoginMenu.js: Um widget que exibe um dos seguintes conjuntos de links:- Gerenciamento de perfil de usuário e links de logout quando o usuário é autenticado.
- Links de registro e login quando o usuário não está autenticado.
-
AuthorizeRoute.js: Um componente de rota que requer que um usuário seja autenticado antes de renderizar o componente indicado no parâmetroComponent.
-
- Uma instância
authServiceexportada de classeAuthorizeServiceque lida com os detalhes de nível inferior do processo de autenticação e expõe informações sobre o usuário autenticado ao restante do aplicativo para consumo.
Agora que você já viu os principais componentes da solução, você pode dar uma olhada mais profunda em cenários individuais para o aplicativo.
Exigir autorização em uma nova API
Por padrão, o sistema é configurado para exigir facilmente autorização para novas APIs. Para fazer isso, crie um novo controlador e adicione o atributo [Authorize] à classe controller ou a qualquer ação dentro do controller.
Personalizar o manipulador de autenticação de API
Para personalizar a configuração do manipulador JWT da API, configure sua JwtBearerOptions instância:
services.AddAuthentication()
.AddIdentityServerJwt();
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
...
});
O manipulador JWT da API gera eventos que permitem o controle sobre o processo de autenticação usando JwtBearerEvents. Para fornecer suporte para autorização de API, AddIdentityServerJwt registra seus próprios manipuladores de eventos.
Para personalizar a manipulação de um evento, envolva o manipulador de eventos existente com lógica adicional, conforme necessário. Por exemplo:
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
var onTokenValidated = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
await onTokenValidated(context);
...
}
});
No código anterior, o manipulador de eventos OnTokenValidated é substituído por uma implementação personalizada. Esta implementação:
- Chama a implementação original fornecida pelo suporte de autorização da API.
- Execute sua própria lógica personalizada.
Proteger uma rota do lado do cliente (Angular)
A proteção de uma rota do lado do cliente é feita adicionando a salvaguarda de autorização à lista de salvaguardas a serem executadas ao configurar uma rota. Como exemplo, você pode ver como a rota fetch-data está configurada no módulo Angular do aplicativo principal:
RouterModule.forRoot([
// ...
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])
É importante mencionar que proteger uma rota não protege o ponto de extremidade real (que ainda requer um atributo [Authorize] aplicado a ele), mas que só impede que o usuário navegue para a rota do lado do cliente quando ela não é autenticada.
Autenticar solicitações de API (Angular)
A autenticação de solicitações em APIs hospedadas ao lado do aplicativo é feita automaticamente por meio do uso do intercetador de cliente HTTP definido pelo aplicativo.
Proteger uma rota do lado do cliente (React)
Proteja uma rota do lado do cliente usando o componente AuthorizeRoute em vez do componente Route simples. Por exemplo, observe como a rota fetch-data é configurada dentro do componente App:
<AuthorizeRoute path='/fetch-data' component={FetchData} />
Proteger uma rota:
- Não protege o ponto de extremidade real (que ainda requer um atributo
[Authorize]aplicado a ele). - Só impede que o usuário navegue até a rota do lado do cliente quando ela não estiver autenticada.
Autenticar solicitações de API (React)
A autenticação de solicitações com o React é feita importando primeiro a instância authService do AuthorizeService. O token de acesso é recuperado do authService e é anexado à solicitação, conforme mostrado abaixo. Nos componentes do React, esse trabalho geralmente é feito no método de ciclo de vida do componentDidMount ou como resultado de alguma interação do usuário.
Importar o authService para um componente
import authService from './api-authorization/AuthorizeService'
Recuperar e anexar o token de acesso à resposta
async populateWeatherData() {
const token = await authService.getAccessToken();
const response = await fetch('api/SampleData/WeatherForecasts', {
headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
Implantar na produção
Para implantar o aplicativo na produção, os seguintes recursos precisam ser provisionados:
- Um banco de dados para armazenar as contas de usuário Identity e as concessões do IdentityServer.
- Um certificado de produção para usar na assinatura de tokens.
- Não existem requisitos específicos para este certificado; pode ser um certificado autoassinado ou um certificado provisionado por meio de uma autoridade de certificação.
- Ele pode ser gerado através de ferramentas padrão como PowerShell ou OpenSSL.
- O certificado pode ser instalado na loja de certificados das máquinas de destino ou implantado como um arquivo .pfx com uma senha forte.
Exemplo: Implantar em um provedor de hospedagem na Web que não seja do Azure
No seu painel de alojamento web, crie ou carregue o seu certificado. Em seguida, no arquivo appsettings.json do aplicativo, modifique a seção IdentityServer para incluir os principais detalhes. Por exemplo:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "WebHosting",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
No exemplo anterior:
-
StoreNamerepresenta o nome do armazenamento de certificados onde o certificado está armazenado. Neste caso, aponta para a loja de alojamento web. -
StoreLocationrepresenta de onde carregar o certificado (CurrentUserneste caso). -
Namecorresponde ao assunto distinguido para o certificado.
Exemplo: Implantar no Serviço de Aplicativo do Azure
Esta seção descreve a implantação do aplicativo no Serviço de Aplicativo do Azure usando um certificado armazenado no repositório de certificados. Para modificar o aplicativo para carregar um certificado do repositório de certificados, um plano de serviço de camada Standard ou superior é necessário quando você configura o aplicativo no portal do Azure em uma etapa posterior.
No arquivo appsettings.json do aplicativo, modifique a seção IdentityServer para incluir os principais detalhes:
"IdentityServer": {
"Key": {
"Type": "Store",
"StoreName": "My",
"StoreLocation": "CurrentUser",
"Name": "CN=MyApplication"
}
}
- O nome do repositório representa o nome do repositório de certificados onde o certificado está armazenado. Neste caso, ele aponta para a loja pessoal do utilizador.
- O local da loja representa onde se deve carregar o certificado (
CurrentUserouLocalMachine). - A propriedade nome no certificado corresponde ao sujeito distinto do certificado.
Para implantar a aplicação no Azure App Service, siga as etapas em Implantar a aplicação no Azure, que explicam como criar os recursos necessários do Azure e implantar a aplicação em produção.
Depois de seguir as instruções anteriores, o aplicativo é implantado no Azure, mas ainda não está funcional. O certificado usado pelo aplicativo deve ser configurado no portal do Azure. Encontre a impressão digital do certificado e siga as etapas descritas em Carregue os seus certificados.
Embora essas etapas mencionem SSL, há uma seção Certificados privados no portal do Azure onde você pode carregar o certificado provisionado para usar com o aplicativo.
Depois de definir o aplicativo e as configurações do aplicativo no portal do Azure, reinicie o aplicativo no portal.
Outras opções de configuração
O suporte para autorização de API se baseia no IdentityServer com um conjunto de convenções, valores padrão e aprimoramentos para simplificar a experiência de SPAs. Não é necessário dizer que todo o poder do IdentityServer está disponível nos bastidores, caso as integrações do ASP.NET Core não cubram o seu cenário. O suporte ASP.NET Core é focado em aplicativos "primários", onde todos os aplicativos são criados e implantados pela nossa organização. Como tal, não é oferecido suporte para aspetos como consentimento ou federação. Para esses cenários, use o IdentityServer e siga sua documentação.
Perfis de aplicação
Os perfis de aplicativo são configurações predefinidas para aplicativos que definem ainda mais seus parâmetros. Neste momento, os seguintes perfis são suportados:
-
IdentityServerSPA: Representa um SPA hospedado ao lado do IdentityServer como uma única unidade.- O
redirect_uriassume como padrão/authentication/login-callback. - O
post_logout_redirect_uriassume como padrão/authentication/logout-callback. - O conjunto de escopos inclui o
openid,profilee todos os escopos definidos para as APIs no aplicativo. - O conjunto de tipos de resposta OIDC permitidos é
id_token tokenou cada um deles individualmente (id_token,token). - O modo de resposta permitido é
fragment.
- O
-
SPA: Representa um SPA que não está hospedado com IdentityServer.- O conjunto de escopos inclui o
openid,profilee todos os escopos definidos para as APIs no aplicativo. - O conjunto de tipos de resposta OIDC permitidos é
id_token tokenou cada um deles individualmente (id_token,token). - O modo de resposta permitido é
fragment.
- O conjunto de escopos inclui o
-
IdentityServerJwt: Representa uma API hospedada junto com o IdentityServer.- O aplicativo está configurado para ter um único escopo que assume como padrão o nome do aplicativo.
-
API: Representa uma API que não está hospedada com o IdentityServer.- O aplicativo está configurado para ter um único escopo que assume como padrão o nome do aplicativo.
Configuração através do AppSettings
Configure as aplicações através do sistema de configuração, adicionando-as à lista de Clients ou Resources.
Configure a propriedade redirect_uri e post_logout_redirect_uri de cada cliente, conforme mostrado no exemplo a seguir:
"IdentityServer": {
"Clients": {
"MySPA": {
"Profile": "SPA",
"RedirectUri": "https://www.example.com/authentication/login-callback",
"LogoutUri": "https://www.example.com/authentication/logout-callback"
}
}
}
Ao configurar recursos, você pode configurar os escopos para o recurso conforme mostrado abaixo:
"IdentityServer": {
"Resources": {
"MyExternalApi": {
"Profile": "API",
"Scopes": "a b c"
}
}
}
Configuração através de código
Você também pode configurar os clientes e recursos por meio de código usando uma sobrecarga de AddApiAuthorization que executa uma ação para configurar opções.
AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.Clients.AddSPA(
"My SPA", spa =>
spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
.WithLogoutRedirectUri(
"http://www.example.com/authentication/logout-callback"));
options.ApiResources.AddApiResource("MyExternalApi", resource =>
resource.WithScopes("a", "b", "c"));
});