ASP.NET核心JWT承载令牌自定义validation

经过大量阅读,我找到了一种实现自定义JWT承载令牌validation器的方法,如下所示。

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(Options.Create(tokenProviderOptions)); } 

以下是自定义validation器类:

 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; } } 

如果被盗令牌,我想添加一个额外的安全层来validation请求是来自生成令牌的同一客户端。

问题:

  1. 有没有办法我可以访问CustomJwtSecurityTokenHandler类中的HttpContext ,以便我可以添加基于当前客户端/请求者的自定义validation?
  2. 有没有其他方法可以使用这样的方法/中间件validation请求者的真实性?

在ASP.NET Core中,可以使用IHttpContextAccessor服务获取HttpContext 。 使用DI将IHttpContextAccessor实例传递到您的处理程序并获取IHttpContextAccessor.HttpContext属性的值。

默认情况下, IHttpContextAccessor服务未注册,因此您首先需要在Startup.ConfigureServices方法中添加以下内容:

 services.TryAddSingleton(); 

然后修改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文档。


更新:如何手动解决依赖关系( 此处有更多信息)

修改Configure方法以使用IServiceProvider serviceProvider

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

由于我无法在任何地方找到答案,因此我将有关HttpContext的validation逻辑移至ActionFilter

但是,它确实使解决方案分散。

对于自定义JWTvalidation器,我在IOAuthBearerAuthenticationProvider中创建了一个JWTCosumerProvider类。 并实现ValidateIdentity()方法来检查我在第一时间存储客户端IP地址的身份声明,然后与之后的当前请求ID地址进行比较。

 public Task ValidateIdentity(OAuthValidateIdentityContext context) { var requestIPAddress = context.Ticket.Identity.FindFirst(ClaimTypes.Dns)?.Value; if (requestIPAddress == null) context.SetError("Token Invalid", "The IP Address not right"); string clientAddress = JWTHelper.GetClientIPAddress(); if (!requestIPAddress.Equals(clientAddress)) context.SetError("Token Invalid", "The IP Address not right"); return Task.FromResult(null); } 

JWTHelper.GetClientIPAddress()

 internal static string GetClientIPAddress() { System.Web.HttpContext context = System.Web.HttpContext.Current; string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; if (!string.IsNullOrEmpty(ipAddress)) { string[] addresses = ipAddress.Split(','); if (addresses.Length != 0) { return addresses[0]; } } return context.Request.ServerVariables["REMOTE_ADDR"]; } 

希望这个帮助!