c# - ASP.NET Core JWT Bearer Token 自定义验证

标签 c# asp.net asp.net-core jwt asp.net-core-middleware

经过大量阅读,我找到了一种实现自定义 JWT 不记名 token 验证器的方法,如下所示。

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

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

问题:

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

最佳答案

在 ASP.NET Core 中,可以使用 IHttpContextAccessor 服务获取 HttpContext。使用 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);
    ...
}

关于c# - ASP.NET Core JWT Bearer Token 自定义验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44179525/

相关文章:

ASP.NET HTTP 错误 500.19 "cannot read config file"

c# - lock 语句如何确保处理器内同步?

c# - Sqlite 查询不在 C# 中返回数据

asp.net - 检查 css 类是否存在于代码隐藏的样式表文件中

c# - 是否有比使用 IAsyncActionFilter 授权更好的方法来授权用户是否处于角色或用户 ID 在数据库中以获取特定记录

c# - MySqlException : Data too long for column 'Id' at row 1

c# - .NET Core Web API/Angular 应用程序中的 Windows 身份验证

c# - 从 Windows Phone 10 上的 FileOpenPicker 访问相机

c# - 如何在 C# 中调整图像的大小以保持纵横比

c# - 通过sqlquery C#检查数据库中的空值