Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
764 views
in Technique[技术] by (71.8m points)

c# - ASP.NET Core JWT Bearer Token Custom Validation

After a lot of reading, I have found a way to implement a custom JWT bearer token validator as below.

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

Custom validator class:

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

In case of stolen token, I would like to add an additional layer of security to validate that the request is coming from the same client who generated the token.

Questions:

  1. Is there any way I can access HttpContext within the CustomJwtSecurityTokenHandler class so that I could add custom validations based on the current client/requestor?
  2. Is there any other way we can validate the authenticity of the requestor using such method/middleware?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In ASP.NET Core, HttpContext could be obtained using IHttpContextAccessor service. Use DI to pass IHttpContextAccessor instance into your handler and get value of IHttpContextAccessor.HttpContext property.

IHttpContextAccessor service is not registered by default, so you first need to add the following in your Startup.ConfigureServices method:

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

then modify your CustomJwtSecurityTokenHandler class:

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

You should also use DI technique for JwtSecurityTokenHandler instantiation. Look into Dependency Injection documentation if you are new to all this stuff.


Update: how to manually resolve dependencies (more info here)

modify Configure method to use 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);
    ...
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...