Middleware de autenticación ASP.NET Core 2.0

Con Core 1.1 siguió el consejo de @ blowdart e implementó un middleware personalizado:

https://stackoverflow.com/a/31465227/29821

Funcionó así:

  1. Middleware funcionó. Recogió un token de los encabezados de solicitud.
  2. Verificado el token y si es válido creó una identidad (ClaimsIdentity) que contenía varias afirmaciones que luego se agregó a través de HttpContext.User.AddIdentity ();
  3. En ConfigureServices using services.AddAuthorization Agregué una política para exigir el reclamo que proporciona el middleware.
  4. En los controladores / acciones usaría [Autorizar (Roles = “algún rol que el middleware agregó”)]

Esto de alguna manera funciona con 2.0, excepto que si el token no es válido (paso 2 anterior) y el reclamo nunca se agrega, obtengo “No se especificó ningún AuthenticationScheme, y no se encontró DefaultChallengeScheme”.

Así que ahora estoy leyendo que auth cambió en 2.0:

https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x

¿Cuál es el camino correcto para hacer lo mismo en ASP.NET Core 2.0? No veo un ejemplo para hacer una autenticación realmente personalizada.

Entonces, después de un largo día tratando de resolver este problema, finalmente descubrí cómo Microsoft quiere que nosotros hagamos manejadores de autenticación personalizados para su nueva configuración de middleware único en el núcleo 2.0.

Después de revisar parte de la documentación en MSDN, encontré una clase llamada AuthenticationHandler que implementa la interfaz IAuthenticationHandler .

A partir de ahí, encontré una base de código completa con los esquemas de autenticación existentes ubicados en https://github.com/aspnet/Security

Dentro de uno de estos, se muestra cómo Microsoft implementa el esquema de autenticación JwtBearer. ( https://github.com/aspnet/Security/tree/dev/src/Microsoft.AspNetCore.Authentication.JwtBearer )

Copié la mayor parte de ese código en una nueva carpeta y JwtBearer todas las cosas que tienen que ver con JwtBearer .

En la clase JwtBearerHandler (que amplía AuthenticationHandler<> ), hay una modificación para Task HandleAuthenticateAsync()

Agregué en nuestro viejo middleware para configurar reclamaciones a través de un servidor de token personalizado, y todavía tenía algunos problemas con los permisos, solo escupiendo un 200 OK lugar de un 401 Unauthorized cuando un token no era válido y no se configuraron reclamos.

Me di cuenta de que había anulado Task HandleChallengeAsync(AuthenticationProperties properties) que por cualquier razón se usa para configurar permisos a través de [Authorize(Roles="")] en un controlador.

Después de eliminar esta anulación, el código había funcionado y arrojó con éxito un 401 cuando los permisos no coincidían.

La conclusión principal de esto es que ahora no puede usar un middleware personalizado, debe implementarlo a través de AuthenticationHandler<> y debe establecer DefaultAuthenticateScheme y DefaultChallengeScheme al usar services.AddAuthentication(...) .

Aquí hay un ejemplo de cómo debería ser todo esto:

En Startup.cs / ConfigureServices () agregue:

 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 => { }); 

En Startup.cs / Configure () agregue:

 app.UseAuthentication(); 

Crea un nuevo archivo CustomAuthExtensions.cs

 public static class CustomAuthExtensions { public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder, Action configureOptions) { return builder.AddScheme("Custom Scheme", "Custom Auth", configureOptions); } } 

Crea un nuevo archivo CustomAuthOptions.cs

 public class CustomAuthOptions: AuthenticationSchemeOptions { public CustomAuthOptions() { } } 

Crea un nuevo archivo CustomAuthHandler.cs

 internal class CustomAuthHandler : AuthenticationHandler { public CustomAuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { // store custom services here... } protected override async Task HandleAuthenticateAsync() { // build the claims and put them in "Context"; you need to import the Microsoft.AspNetCore.Authentication package return AuthenticateResult.NoResult(); } } 

Existen cambios considerables en Identity from Core 1.x a Core 2.0 como lo indica el artículo que referencia. El principal cambio es alejarse del enfoque de middleware y usar la dependency injection para configurar servicios personalizados. Esto proporciona mucha más flexibilidad en la personalización de la identidad para implementaciones más complejas. Entonces quiere alejarse del enfoque de middleware que menciona arriba y avanzar hacia los servicios. Siga los pasos de migración en el artículo al que se hace referencia para lograr este objective. Comience por reemplazar app.UseIdentity con app.UseAuthentication . UseIdentity se deprecia y no será compatible en futuras versiones. Para ver un ejemplo completo de cómo insertar una transformación de reclamos personalizada y realizar una autorización en el reclamo, vea esta publicación de blog .