É possível oferecer suporte a vários emissores de token JWT no ASP.NET Core 2? Quero fornecer uma API para serviço externo e preciso usar duas fontes de tokens JWT - Firebase e emissores de tokens JWT personalizados. No ASP.NET core, posso definir a autenticação JWT para o esquema de autenticação do Bearer, mas apenas para uma autoridade:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://securetoken.google.com/my-firebase-project"
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "my-firebase-project"
ValidateAudience = true,
ValidAudience = "my-firebase-project"
ValidateLifetime = true
};
}
Posso ter vários emissores e públicos, mas não consigo definir várias autoridades.
Respostas:
Você pode alcançar totalmente o que deseja:
services .AddAuthentication() .AddJwtBearer("Firebase", options => { options.Authority = "https://securetoken.google.com/my-firebase-project" options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "my-firebase-project" ValidateAudience = true, ValidAudience = "my-firebase-project" ValidateLifetime = true }; }) .AddJwtBearer("Custom", options => { // Configuration for your custom // JWT tokens here }); services .AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes("Firebase", "Custom") .Build(); });
Vamos examinar as diferenças entre o seu código e aquele.
AddAuthentication
não tem parâmetroSe você definir um esquema de autenticação padrão, a cada solicitação, o middleware de autenticação tentará executar o manipulador de autenticação associado ao esquema de autenticação padrão. Já que agora temos dois esquemas de autenticação acessíveis, não há sentido em executar um deles.
Use outra sobrecarga de
AddJwtBearer
Cada
AddXXX
método para adicionar uma autenticação tem várias sobrecargas:Agora, como você usa o mesmo método de autenticação duas vezes, mas os esquemas de autenticação devem ser exclusivos, você precisa usar a segunda sobrecarga.
Atualize a política padrão
Como as solicitações não serão mais autenticadas automaticamente, colocar
[Authorize]
atributos em algumas ações resultará na rejeição das solicitações e naHTTP 401
emissão de um.Como não queremos isso porque queremos dar aos manipuladores de autenticação a chance de autenticar a solicitação, alteramos a política padrão do sistema de autorização indicando que os esquemas de autenticação
Firebase
eCustom
devem ser tentados para autenticar a solicitação.Isso não o impede de ser mais restritivo em algumas ações; o
[Authorize]
atributo tem umaAuthenticationSchemes
propriedade que permite substituir quais esquemas de autenticação são válidos.Se você tiver cenários mais complexos, pode usar a autorização baseada em políticas . Acho que a documentação oficial é ótima.
Vamos imaginar que algumas ações estão disponíveis apenas para tokens JWT emitidos pelo Firebase e devem ter uma declaração com um valor específico; você poderia fazer desta forma:
// Authentication code omitted for brevity services .AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes("Firebase", "Custom") .Build(); options.AddPolicy("FirebaseAdministrators", new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes("Firebase") .RequireClaim("role", "admin") .Build()); });
Você pode então usar
[Authorize(Policy = "FirebaseAdministrators")]
em algumas ações.Um último ponto a ser observado: se você estiver capturando
AuthenticationFailed
eventos e usando qualquer coisa que não seja a primeiraAddJwtBearer
política, verá queIDX10501: Signature validation failed. Unable to match key...
isso é causado pelo sistema verificando cada umAddJwtBearer
por vez até obter uma correspondência. O erro geralmente pode ser ignorado.fonte
Authorization : Bearer <token>
que o cabeçalho sejaAuthorization : Firebase <token>
por exemplo? Quando tentei esta solução, obtive o erro: "Nenhum manipulador de autenticação está registrado para o esquema 'Portador'.".AddJwtBearer
chamadas de método.[Authorize]
atributo vazio .Esta é uma extensão da resposta de Mickaël Derriey.
Nosso aplicativo tem um requisito de autorização personalizada que resolvemos de uma fonte interna. Estávamos usando Auth0, mas estamos mudando para a autenticação de conta da Microsoft usando OpenID. Aqui está o código ligeiramente editado de nossa inicialização ASP.Net Core 2.1. Para futuros leitores, isso funciona até o momento desta redação para as versões especificadas. O chamador usa o id_token do OpenID em solicitações de entrada passadas como um token do portador. Espero que ajude alguém tentando fazer uma conversão de autoridade de identidade tanto quanto esta pergunta e resposta me ajudou.
const string Auth0 = nameof(Auth0); const string MsaOpenId = nameof(MsaOpenId); string domain = "https://myAuth0App.auth0.com/"; services.AddAuthentication() .AddJwtBearer(Auth0, options => { options.Authority = domain; options.Audience = "https://myAuth0Audience.com"; }) .AddJwtBearer(MsaOpenId, options => { options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { ValidateAudience = true, ValidAudience = "00000000-0000-0000-0000-000000000000", ValidateIssuer = true, ValidIssuer = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0", ValidateIssuerSigningKey = true, RequireExpirationTime = true, ValidateLifetime = true, RequireSignedTokens = true, ClockSkew = TimeSpan.FromMinutes(10), }; options.MetadataAddress = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0/.well-known/openid-configuration"; } ); services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes( Auth0, MsaOpenId ) .Build(); var approvedPolicyBuilder = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes(Auth0, MsaOpenId) ; approvedPolicyBuilder.Requirements.Add(new HasApprovedRequirement(domain)); options.AddPolicy("approved", approvedPolicyBuilder.Build()); });
fonte