Esquemas de políticas no ASP.NET Core
Os esquemas de política de autenticação facilitam que um único esquema de autenticação lógica use potencialmente várias abordagens. Por exemplo, um esquema de políticas pode usar a autenticação do Google para desafios e a autenticação cookie para todo o resto. Os esquemas de política de autenticação permitem:
- Fácil de encaminhar qualquer ação de autenticação para outro esquema.
- Encaminhar dinamicamente com base na solicitação.
Todos os esquemas de autenticação que usam AuthenticationSchemeOptions derivados e os AuthenticationHandler<TOptions>associados:
- São esquemas de política automatizados no ASP.NET Core 2.1 e posteriores.
- Pode ser ativado através da configuração das opções do esquema.
public class AuthenticationSchemeOptions
{
/// <summary>
/// If set, this specifies a default scheme that authentication handlers should
/// forward all authentication operations to, by default. The default forwarding
/// logic checks in this order:
/// 1. The most specific ForwardAuthenticate/Challenge/Forbid/SignIn/SignOut
/// 2. The ForwardDefaultSelector
/// 3. ForwardDefault
/// The first non null result is used as the target scheme to forward to.
/// </summary>
public string ForwardDefault { get; set; }
/// <summary>
/// If set, this specifies the target scheme that this scheme should forward
/// AuthenticateAsync calls to. For example:
/// Context.AuthenticateAsync("ThisScheme") =>
/// Context.AuthenticateAsync("ForwardAuthenticateValue");
/// Set the target to the current scheme to disable forwarding and allow
/// normal processing.
/// </summary>
public string ForwardAuthenticate { get; set; }
/// <summary>
/// If set, this specifies the target scheme that this scheme should forward
/// ChallengeAsync calls to. For example:
/// Context.ChallengeAsync("ThisScheme") =>
/// Context.ChallengeAsync("ForwardChallengeValue");
/// Set the target to the current scheme to disable forwarding and allow normal
/// processing.
/// </summary>
public string ForwardChallenge { get; set; }
/// <summary>
/// If set, this specifies the target scheme that this scheme should forward
/// ForbidAsync calls to.For example:
/// Context.ForbidAsync("ThisScheme")
/// => Context.ForbidAsync("ForwardForbidValue");
/// Set the target to the current scheme to disable forwarding and allow normal
/// processing.
/// </summary>
public string ForwardForbid { get; set; }
/// <summary>
/// If set, this specifies the target scheme that this scheme should forward
/// SignInAsync calls to. For example:
/// Context.SignInAsync("ThisScheme") =>
/// Context.SignInAsync("ForwardSignInValue");
/// Set the target to the current scheme to disable forwarding and allow normal
/// processing.
/// </summary>
public string ForwardSignIn { get; set; }
/// <summary>
/// If set, this specifies the target scheme that this scheme should forward
/// SignOutAsync calls to. For example:
/// Context.SignOutAsync("ThisScheme") =>
/// Context.SignOutAsync("ForwardSignOutValue");
/// Set the target to the current scheme to disable forwarding and allow normal
/// processing.
/// </summary>
public string ForwardSignOut { get; set; }
/// <summary>
/// Used to select a default scheme for the current request that authentication
/// handlers should forward all authentication operations to by default. The
/// default forwarding checks in this order:
/// 1. The most specific ForwardAuthenticate/Challenge/Forbid/SignIn/SignOut
/// 2. The ForwardDefaultSelector
/// 3. ForwardDefault.
/// The first non null result will be used as the target scheme to forward to.
/// </summary>
public Func<HttpContext, string> ForwardDefaultSelector { get; set; }
}
JWT com vários esquemas
O método AddPolicyScheme pode definir vários esquemas de autenticação e implementar lógica para selecionar o esquema apropriado com base nas propriedades do token (por exemplo, emissor, declarações). Essa abordagem permite maior flexibilidade dentro de uma única API.
services.AddAuthentication(options =>
{
options.DefaultScheme = Consts.MY_POLICY_SCHEME;
options.DefaultChallengeScheme = Consts.MY_POLICY_SCHEME;
})
.AddJwtBearer(Consts.MY_FIRST_SCHEME, options =>
{
options.Authority = "https://your-authority";
options.Audience = "https://your-audience";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidAudiences = Configuration.GetSection("ValidAudiences").Get<string[]>(),
ValidIssuers = Configuration.GetSection("ValidIssuers").Get<string[]>()
};
})
.AddJwtBearer(Consts.MY_AAD_SCHEME, jwtOptions =>
{
jwtOptions.Authority = Configuration["AzureAd:Authority"];
jwtOptions.Audience = Configuration["AzureAd:Audience"];
})
.AddPolicyScheme(Consts.MY_POLICY_SCHEME, displayName: null, options =>
{
options.ForwardDefaultSelector = context =>
{
string authorization = context.Request.Headers[HeaderNames.Authorization];
if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer "))
{
var token = authorization.Substring("Bearer ".Length).Trim();
var jwtHandler = new JsonWebTokenHandler();
if(jwtHandler.CanReadToken(token)) // it's a self contained access token and not encrypted
{
var issuer = jwtHandler.ReadJsonWebToken(token).Issuer; //.Equals("B2C-Authority"))
if (issuer == Consts.MY_THIRD_PARTY_ISS) // Third party identity provider
{
return Consts.MY_THIRD_PARTY_SCHEME;
}
if (issuer == Consts.MY_AAD_ISS) // AAD
{
return Consts.MY_AAD_SCHEME;
}
}
}
// We don't know with it is
return Consts.MY_AAD_SCHEME;
};
});
Exemplos
O exemplo a seguir mostra um esquema de nível superior que combina esquemas de nível inferior. A autenticação do Google é usada para desafios e a autenticação cookie é usada para todo o resto:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => options.ForwardChallenge = "Google")
.AddGoogle(options => { });
}
O exemplo a seguir permite a seleção dinâmica de esquemas por solicitação. Ou seja, como misturar cookies e autenticação API:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
// For example, can foward any requests that start with /api
// to the api scheme.
options.ForwardDefaultSelector = ctx =>
ctx.Request.Path.StartsWithSegments("/api") ? "Api" : null;
})
.AddYourApiAuth("Api");
}