Então, depois de um longo dia tentando resolver esse problema, eu finalmente descobri como a Microsoft quer que façamos manipuladores de autenticação personalizados para sua nova configuração de middleware único no núcleo 2.0.
Depois de examinar parte da documentação do MSDN, encontrei uma classe chamada AuthenticationHandler<TOption>
que implementa a IAuthenticationHandler
interface.
A partir daí, encontrei uma base de código inteira com os esquemas de autenticação existentes localizados em https://github.com/aspnet/Security
Dentro de um deles, ele mostra como a Microsoft implementa o esquema de autenticação JwtBearer. ( https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer )
Copiei a maior parte desse código para uma nova pasta e limpei todas as coisas relacionadas com JwtBearer
.
Na JwtBearerHandler
classe (que estende AuthenticationHandler<>
), há uma substituição paraTask<AuthenticateResult> HandleAuthenticateAsync()
Eu adicionei nosso middleware antigo para configurar declarações por meio de um servidor de token personalizado e ainda estava encontrando alguns problemas com permissões, apenas emitindo um em 200 OK
vez de um 401 Unauthorized
quando um token era inválido e nenhuma declaração foi configurada.
Percebi que havia substituído o Task HandleChallengeAsync(AuthenticationProperties properties)
qual, por qualquer motivo, é usado para definir permissões por meio [Authorize(Roles="")]
de um controlador.
Depois de remover essa substituição, o código funcionou e lançou um 401
quando as permissões não coincidiram.
A principal conclusão disso é que agora você não pode usar um middleware personalizado, você deve implementá-lo via AuthenticationHandler<>
e definir o DefaultAuthenticateScheme
e DefaultChallengeScheme
ao usar services.AddAuthentication(...)
.
Aqui está um exemplo de como tudo isso deve ser:
Em Startup.cs / ConfigureServices (), adicione:
services.AddAuthentication(options =>
{
// the scheme name has to match the value we're going to use in AuthenticationBuilder.AddScheme(...)
options.DefaultAuthenticateScheme = "Custom Scheme";
options.DefaultChallengeScheme = "Custom Scheme";
})
.AddCustomAuth(o => { });
Em Startup.cs / Configure () adicione:
app.UseAuthentication();
Crie um novo arquivo CustomAuthExtensions.cs
public static class CustomAuthExtensions
{
public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder, Action<CustomAuthOptions> configureOptions)
{
return builder.AddScheme<CustomAuthOptions, CustomAuthHandler>("Custom Scheme", "Custom Auth", configureOptions);
}
}
Crie um novo arquivo CustomAuthOptions.cs
public class CustomAuthOptions: AuthenticationSchemeOptions
{
public CustomAuthOptions()
{
}
}
Crie um novo arquivo CustomAuthHandler.cs
internal class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
public CustomAuthHandler(IOptionsMonitor<CustomAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
// store custom services here...
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// build the claims and put them in "Context"; you need to import the Microsoft.AspNetCore.Authentication package
return AuthenticateResult.NoResult();
}
}