2017-10-18 1 views
1

Je souhaite utiliser DI correctement dans ASP.NET Core 2.0 pour que ma méthode personnalisée gère l'événement OnTokenValidated qui se déclenche après la validation d'un jeton JWT lors de l'authentification. La solution ci-dessous fonctionne, sauf que dans le gestionnaire j'utilise un service injecté qui atteint MemoryCache pour vérifier les éléments en cache ajoutés ailleurs dans un contrôleur (j'ai vérifié qu'ils sont ajoutés et persisté), et quand on y accède, le le cache est toujours vide. Je suppose que c'est parce que mon objet gestionnaire personnalisé est créé par un conteneur différent (en raison de l'appel BuildServiceProvider()?) Et utilise une instance distincte de MemoryCache (ou similaire).Problèmes de gestion d'OnTokenValidated avec un délégué affecté dans startup.cs

Si c'est le cas, je suppose que je ne suis pas clair sur la façon d'ajouter correctement et de référencer ma classe et méthode dans ConfigureServices() dans startup.cs afin que cela fonctionne comme prévu. Voici ce que j'ai:

public void ConfigureServices(IServiceCollection services) 
    { 
    services.AddMemoryCache(); 
    ... 
    services.AddScoped<IJwtTokenValidatedHandler, JwtTokenValidatedHandler>(); 
    // add other services 
    ... 
    var sp = services.BuildServiceProvider(); 
    services.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, bOptions => 
     { 
      // Configure JwtBearerOptions 
      bOptions.Events = new JwtBearerEvents 
      { 
       OnTokenValidated = sp.GetService<JwtTokenValidatedHandler>().JwtTokenValidated 
      }; 
     } 

Ma classe de gestionnaire personnalisée est ci-dessous. L'appel ValidateSessionAsync() utilise une injection AppSessionService pour accéder à l'objet MemoryCache et d'assurer une entrée de cache existe:

public class JwtTokenValidatedHandler : IJwtTokenValidatedHandler 
{ 
    AppSessionService _session; 
    public JwtTokenValidatedHandler(AppSessionService session) 
    { 
     _session = session; 
    } 
    public async Task JwtTokenValidated(TokenValidatedContext context) 
    { 
     // Add the access_token as a claim, as we may actually need it 
     var accessToken = context.SecurityToken as JwtSecurityToken; 
     if (Guid.TryParse(accessToken.Id, out Guid sessionId)) 
     { 
      if (await _session.ValidateSessionAsync(sessionId)) 
      { 
       return; 
      } 
     } 
     throw new SecurityTokenValidationException("Session not valid for provided token."); 
    } 
} 

Si la méthode personnalisée OnTokenValidated contenait une logique simple et n'a pas besoin d'un service injecté Je le en ligne avec une fonction anonyme ou déclarez-le en privé dans startup.cs. Je préférerais corriger cette approche si je peux, mais je serais ouvert à d'autres.

Répondre

1

Au lieu d'utiliser des événements statiques/singleton, pensez JwtBearerEvents et le sous-classement en utilisant l'option JwtBearerOptions.EventsType:

public class CustomJwtBearerEvents : JwtBearerEvents 
{ 
    AppSessionService _session; 
    public CustomJwtBearerEvents(AppSessionService session) 
    { 
     _session = session; 
    } 

    public override async Task TokenValidated(TokenValidatedContext context) 
    { 
     // Add the access_token as a claim, as we may actually need it 
     var accessToken = context.SecurityToken as JwtSecurityToken; 
     if (Guid.TryParse(accessToken.Id, out Guid sessionId)) 
     { 
      if (await _session.ValidateSessionAsync(sessionId)) 
      { 
       return; 
      } 
     } 
     throw new SecurityTokenValidationException("Session not valid for provided token."); 
    } 
} 

public class Startup 
{ 
    public void ConfigureServices(IServiceCollection services) 
    { 
     services.AddScoped<CustomJwtBearerEvents>(); 

     services.AddAuthentication() 
      .AddJwtBearer(options => 
      { 
       options.EventsType = typeof(CustomJwtBearerEvents); 
      }); 
    } 
} 
+0

Yep. Cela a fait l'affaire! – coryseaman