2017-05-25 108 views
3

經過大量閱讀,我找到了一種實現自定義JWT不記名令牌驗證器的方法,如下所示。ASP.NET核心JWT承載令牌自定義驗證

Starup.cs代碼:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
     ILoggerFactory loggerFactory, IApplicationLifetime appLifetime) 
{ 
    loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
    loggerFactory.AddDebug(); 

    app.UseStaticFiles(); 

    app.UseIdentity(); 

    ConfigureAuth(app); 

    app.UseMvcWithDefaultRoute();    
} 

private void ConfigureAuth(IApplicationBuilder app) 
    { 

     var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("TokenAuthentication:SecretKey").Value)); 


     var tokenValidationParameters = new TokenValidationParameters 
     { 
      // The signing key must match! 
      ValidateIssuerSigningKey = true, 
      IssuerSigningKey = signingKey, 
      // Validate the JWT Issuer (iss) claim 
      ValidateIssuer = true, 
      ValidIssuer = Configuration.GetSection("TokenAuthentication:Issuer").Value, 
      // Validate the JWT Audience (aud) claim 
      ValidateAudience = true, 
      ValidAudience = Configuration.GetSection("TokenAuthentication:Audience").Value, 
      // Validate the token expiry 
      ValidateLifetime = true, 
      // If you want to allow a certain amount of clock drift, set that here: 
      ClockSkew = TimeSpan.Zero 
     }; 

     var jwtBearerOptions = new JwtBearerOptions(); 
     jwtBearerOptions.AutomaticAuthenticate = true; 
     jwtBearerOptions.AutomaticChallenge = true; 
     jwtBearerOptions.TokenValidationParameters = tokenValidationParameters; 
     jwtBearerOptions.SecurityTokenValidators.Clear(); 
     //below line adds the custom validator class 
     jwtBearerOptions.SecurityTokenValidators.Add(new CustomJwtSecurityTokenHandler()); 
     app.UseJwtBearerAuthentication(jwtBearerOptions); 

     var tokenProviderOptions = new TokenProviderOptions 
     { 
      Path = Configuration.GetSection("TokenAuthentication:TokenPath").Value, 
      Audience = Configuration.GetSection("TokenAuthentication:Audience").Value, 
      Issuer = Configuration.GetSection("TokenAuthentication:Issuer").Value, 
      SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256) 
     }; 

     app.UseMiddleware<TokenProviderMiddleware>(Options.Create(tokenProviderOptions)); 
    } 

下面是自定義的驗證類:

public class CustomJwtSecurityTokenHandler : ISecurityTokenValidator 
{ 
    private int _maxTokenSizeInBytes = TokenValidationParameters.DefaultMaximumTokenSizeInBytes; 
    private JwtSecurityTokenHandler _tokenHandler; 

    public CustomJwtSecurityTokenHandler() 
    { 
     _tokenHandler = new JwtSecurityTokenHandler(); 
    } 

    public bool CanValidateToken 
    { 
     get 
     { 
      return true; 
     } 
    } 

    public int MaximumTokenSizeInBytes 
    { 
     get 
     { 
      return _maxTokenSizeInBytes; 
     } 

     set 
     { 
      _maxTokenSizeInBytes = value; 
     } 
    } 

    public bool CanReadToken(string securityToken) 
    { 
     return _tokenHandler.CanReadToken(securityToken);    
    } 

    public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) 
    { 
     //How to access HttpContext/IP address from here? 

     var principal = _tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken); 

     return principal; 
    } 
} 

在被盜令牌的情況下,我想添加額外的安全層,以驗證該請求是來自生成令牌的同一個客戶端。

問題:

  1. 有什麼辦法,我可以在CustomJwtSecurityTokenHandler類中訪問HttpContext這樣我就可以根據當前的客戶端/請求添加自定義的驗證?
  2. 有沒有其他方法可以驗證使用這種方法/中間件的請求者的真實性?
+0

你需要什麼包增加對UseIdentity和TokenValidationParameters? – schmidlop

+0

@schmidlop'Microsoft.AspNetCore.Identity'和'Microsoft.IdentityModel.Tokens'分別。 –

回答

1

在ASP.NET Core HttpContext可以使用IHttpContextAccessor服務獲得。使用DI將IHttpContextAccessor實例傳遞給您的處理程序,並獲得IHttpContextAccessor.HttpContext屬性的值。

IHttpContextAccessor服務不是默認情況下將註冊的,所以你首先需要添加在你Startup.ConfigureServices方法如下:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

然後修改CustomJwtSecurityTokenHandler類:

private readonly IHttpContextAccessor _httpContextAccessor; 

public CustomJwtSecurityTokenHandler(IHttpContextAccessor httpContextAccessor) 
{ 
    _httpContextAccessor = httpContextAccessor; 
    _tokenHandler = new JwtSecurityTokenHandler(); 
} 

... 

public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) 
{ 
    var httpContext = _httpContextAccessor.HttpContext; 
} 

你應該還可以使用DI技術來實現JwtSecurityTokenHandler實例化。如果你是所有這些東西的新手,請查看Dependency Injection文檔。


更新:如何手動解決依賴關係(更多信息here

修改Configure方法使用IServiceProvider serviceProvider

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
     ILoggerFactory loggerFactory, IApplicationLifetime appLifetime, 
     IServiceProvider serviceProvider) 
{ 
    ... 
    var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>(); 
    // and extend ConfigureAuth 
    ConfigureAuth(app, httpContextAccessor); 
    ... 
} 
+0

我明白你想說什麼。然而,如果你看看我的代碼示例,我需要在中間件注入期間傳遞'CustomJwtSecurityTokenHandler'的一個實例。此時,沒有'HttpContext'。處理這種情況是我面臨的主要問題。 –

+0

問題不在於我無法訪問'IHttpContextAccessor'。問題是當'CustomJwtSecurityTokenHandler'被實例化時,'httpContextAccessor。上下文「將爲空。我試圖通過移動我的代碼來實現您的建議,但目前爲止尚未成功。再次感謝您的建議。 –

+1

@SangSuantak。也許現在我明白了你的錯誤,但是:'當CustomJwtSecurityTokenHandler被實例化時,httpContextAccessor.Context將爲空 - 是的,此時上下文不存在,這就是爲什麼在初始化期間你只需要存儲HttpContextAccessor實例,你應該調用' httpContextAccessor.HttpContext'在你的'ValidateToken'方法中,因爲它稍後會在HTTP請求到來時被調用,所以HttpContext將被創建。 – Set

0

由於我無法在任何地方找到答案,因此我將與HttpContext相關的驗證邏輯移至ActionFilter

但是,它確實使解決方案分散。