Middleware de autenticación ASP.NET Core 2.0

89

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

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

Funcionó así:

  1. Se ejecutó el middleware. Recogió un token de los encabezados de la solicitud.
  2. Verificó el token y, si es válido, construyó una identidad (ClaimsIdentity) que contenía múltiples reclamos que luego agregó a través de HttpContext.User.AddIdentity ();
  3. En ConfigureServices usando services.AddAuthorization, agregué una política para requerir el reclamo que proporciona el middleware.
  4. En los controladores / acciones, usaría [Authorize (Roles = "algún rol que agregó el middleware")]

Esto funciona de alguna manera con 2.0, excepto que si el token no es válido (paso 2 anterior) y la reclamación nunca se agrega, obtengo "No se especificó un esquema de autenticación y no se encontró un esquema de desafío predeterminado".

Así que ahora estoy leyendo que la autenticación cambió en 2.0:

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

¿Cuál es la ruta correcta para que yo haga lo mismo en ASP.NET Core 2.0? No veo un ejemplo para hacer una autenticación verdaderamente personalizada.

pbz
fuente
Pruebe este enlace, a pesar de que dice 2 esquemas, pero le avisará
Mithun Pattankar
¿podría agregar su código para que podamos echar un vistazo? Sé que tuve problemas con JWT en core2.0 - fue un caso de moverlo en el inicio
Webezine

Respuestas:

194

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

Después de revisar parte de la documentación de MSDN, encontré una clase llamada AuthenticationHandler<TOption>que implementa la IAuthenticationHandlerinterfaz.

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, muestra cómo Microsoft implementa el esquema de autenticación JwtBearer. ( https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer )

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

En la JwtBearerHandlerclase (que se extiende AuthenticationHandler<>), hay una anulación paraTask<AuthenticateResult> HandleAuthenticateAsync()

Agregué nuestro antiguo middleware para configurar reclamos a través de un servidor de tokens personalizado, y todavía tenía algunos problemas con los permisos, solo escupía un en 200 OKlugar de un 401 Unauthorizedcuando un token no era válido y no se configuraron reclamos.

Me di cuenta de que había anulado lo Task HandleChallengeAsync(AuthenticationProperties properties)que, por cualquier motivo, se usa para establecer permisos a través [Authorize(Roles="")]de un controlador.

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

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

Aquí hay un ejemplo de cómo debería verse 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();

Cree un nuevo archivo 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);
    }
}

Cree un nuevo archivo CustomAuthOptions.cs

public class CustomAuthOptions: AuthenticationSchemeOptions
{
    public CustomAuthOptions()
    {

    }
}

Cree un nuevo archivo 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();
    }
}
Zac
fuente
1
gran publicación, pero tengo algunos problemas para compilar tu código. Faltan los tipos CustomAuthOptions y AuthenticateResult. ¿Podrías publicarlos?
alexb
8
¿Está dispuesto a compartir sus conclusiones en código en un repositorio de Github?
CSharper
2
¿Podría explicar DefaultAuthenticateSchemey DefaultChallengeScheme? No entiendo por qué se usan ambos. y cuáles son las diferencias entre ellos.
Mohammed Noureldin
11
+1 para "A partir de ahí, encontré una base de código completa con los esquemas de autenticación existentes ubicados en github.com/aspnet/Security ". Solo mire cómo lo hace el equipo de ASP.NET mientras sigue esta respuesta (realmente excelente). ¿Alguno de nosotros pensó alguna vez que algún día estaríamos haciendo preguntas sobre el código y las prácticas de MS y la respuesta sería, "sólo eche un vistazo a su código base"?
Marc L.
3
Para otros que lleguen más tarde, AuthExtensiondebe estar dentro del Microsoft.Extensions.DependencyInjectionespacio de nombres. Vea este ejemplo: github.com/aspnet/Security/blob/rel/2.0.0/src/…
Garry Polley
4

Hay cambios considerables en la identidad de Core 1.xa Core 2.0, como señala el artículo al que hace referencia. El cambio principal es alejarse del enfoque de middleware y usar la inyección de dependencia para configurar servicios personalizados. Esto proporciona mucha más flexibilidad a la hora de personalizar Identity para implementaciones más complejas. Por lo tanto, desea alejarse del enfoque de middleware que mencionó anteriormente y avanzar hacia los servicios. Siga los pasos de migración en el artículo de referencia para lograr este objetivo. Comience reemplazando app.UseIdentity con app.UseAuthentication . UseIdentity está depreciado y no será compatible con versiones futuras. Para obtener un ejemplo completo de cómo insertar una transformación de notificaciones personalizada y realizar la autorización en la notificaciónver esta publicación de blog .

Kevin Junghans
fuente
12
¿Hay algún ejemplo sobre cómo usar esto con una aplicación WebAPI?
alexb