Middleware di autenticazione ASP.NET Core 2.0


91

Con Core 1.1 ho seguito il consiglio di @ blowdart e implementato un middleware personalizzato:

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

Funzionava così:

  1. Il middleware è stato eseguito. Raccolto un token dalle intestazioni della richiesta.
  2. Verificato il token e, se valido, ha creato un'identità (ClaimsIdentity) che conteneva più attestazioni che poi ha aggiunto tramite HttpContext.User.AddIdentity ();
  3. In ConfigureServices using services.AddAuthorization ho aggiunto un criterio per richiedere l'attestazione fornita dal middleware.
  4. Nei controller / azioni utilizzerei quindi [Authorize (Roles = "some role that the middleware added")]

Funziona in qualche modo con la 2.0, tranne per il fatto che se il token non è valido (passaggio 2 sopra) e l'attestazione non viene mai aggiunta, ottengo "Non è stato specificato alcun authenticationScheme e non è stato trovato alcun DefaultChallengeScheme".

Quindi ora sto leggendo che l'autenticazione è cambiata nella 2.0:

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

Qual è il percorso giusto per me per fare la stessa cosa in ASP.NET Core 2.0? Non vedo un esempio per eseguire un'autenticazione veramente personalizzata.


Prova questo link, anche se dice 2 schemi ma ti darebbe un avviso
Mithun Pattankar

potresti aggiungere il tuo codice in modo che possiamo dare un'occhiata? So di aver avuto problemi con JWT in core2.0 - è stato un caso di spostarlo all'avvio
Webezine

Risposte:


198

Quindi, dopo una lunga giornata passata a cercare di risolvere questo problema, ho finalmente capito come Microsoft vuole che creiamo gestori di autenticazione personalizzati per la loro nuova configurazione single-middleware nel core 2.0.

Dopo aver esaminato parte della documentazione su MSDN, ho trovato una classe chiamata AuthenticationHandler<TOption>che implementa l' IAuthenticationHandlerinterfaccia.

Da lì, ho trovato un'intera base di codice con gli schemi di autenticazione esistenti situati su https://github.com/aspnet/Security

All'interno di uno di questi, mostra come Microsoft implementa lo schema di autenticazione JwtBearer. ( https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer )

Ho copiato la maggior parte di quel codice in una nuova cartella e ho cancellato tutte le cose che avevano a che fare con JwtBearer.

Nella JwtBearerHandlerclasse (che si estende AuthenticationHandler<>), c'è un override perTask<AuthenticateResult> HandleAuthenticateAsync()

Ho aggiunto il nostro vecchio middleware per l'impostazione delle attestazioni tramite un server token personalizzato e riscontravo ancora alcuni problemi con le autorizzazioni, emettendo semplicemente un 200 OKinvece di un 401 Unauthorizedquando un token non era valido e non erano state configurate rivendicazioni.

Mi sono reso conto che avevo sovrascritto Task HandleChallengeAsync(AuthenticationProperties properties)che per qualsiasi motivo viene utilizzato per impostare le autorizzazioni tramite [Authorize(Roles="")]un controller.

Dopo aver rimosso questo override, il codice aveva funzionato e aveva generato con successo un messaggio di errore 401quando le autorizzazioni non corrispondevano.

Il punto principale è che ora non puoi usare un middleware personalizzato, devi implementarlo tramite AuthenticationHandler<>e devi impostare DefaultAuthenticateSchemee DefaultChallengeSchemequando lo usi services.AddAuthentication(...).

Ecco un esempio di come dovrebbe apparire tutto questo:

In Startup.cs / ConfigureServices () aggiungere:

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

In Startup.cs / Configure () aggiungere:

app.UseAuthentication();

Crea un nuovo file 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);
    }
}

Crea un nuovo file CustomAuthOptions.cs

public class CustomAuthOptions: AuthenticationSchemeOptions
{
    public CustomAuthOptions()
    {

    }
}

Crea un nuovo file 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();
    }
}

1
ottimo post, ma ho qualche problema a compilare il tuo codice. Mancano i tipi CustomAuthOptions e AuthenticateResult. Potresti postarli?
alexb

8
Sei disposto a condividere le tue conclusioni in codice su un repository Github?
CSharper

2
Potresti spiegare DefaultAuthenticateSchemee DefaultChallengeScheme? Non capisco perché vengono utilizzati entrambi? e quali sono le differenze tra loro.
Mohammed Noureldin

11
+1 per "Da lì, ho trovato un'intera base di codice con gli schemi di autenticazione esistenti su github.com/aspnet/Security ". Guarda come lo fa il team ASP.NET mentre segui questa (davvero eccellente) risposta. Qualcuno di noi ha mai pensato che un giorno avremmo posto domande sul codice e sulle pratiche della SM e la risposta sarebbe stata "dai un'occhiata al loro codice base?"
Marc L.

3
Per gli altri che entrano in un secondo momento, AuthExtensiondevi essere all'interno dello Microsoft.Extensions.DependencyInjectionspazio dei nomi. Guarda questo esempio: github.com/aspnet/Security/blob/rel/2.0.0/src/…
Garry Polley

4

Sono stati apportati notevoli cambiamenti in Identity da Core 1.x a Core 2.0 come sottolinea l'articolo a cui fai riferimento. Il cambiamento principale è l'abbandono dell'approccio middleware e l'utilizzo dell'inserimento delle dipendenze per configurare servizi personalizzati. Ciò fornisce molta più flessibilità nella personalizzazione dell'identità per implementazioni più complesse. Quindi vuoi allontanarti dall'approccio middleware che hai menzionato sopra e passare ai servizi. Segui i passaggi della migrazione nell'articolo di riferimento per raggiungere questo obiettivo. Inizia sostituendo app.UseIdentity con app.UseAuthentication . UseIdentity è obsoleto e non sarà supportato nelle versioni future. Per un esempio completo di come inserire una trasformazione delle attestazioni personalizzate ed eseguire l'autorizzazione sulla rivendicazionevisualizza questo post del blog .


12
C'è un esempio su come usarlo con un'app WebAPI?
alexb
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.