当前位置: 首页 > 知识库问答 >
问题:

ASP. NET Core JWT承载令牌自定义验证

葛修筠
2023-03-14

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

启动。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. 我们是否有其他方法可以使用这种方法/中间件验证请求者的真实性

共有3个答案

华建同
2023-03-14

对于自定义JWT验证器,我创建了一个继承到IOAuthBearerAuthentiationProvider的JWTCosumerProvider类。并实现ValidateIdid()方法,首先检查存储客户端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<object>(null);
    }

JWTHelper。######################################################################################

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

希望这有帮助!

姜建德
2023-03-14

只是为了补充另一个解决方案,而不需要注入到ISecurityTokenValidator中,就像

在ISecurityTokenValidator实现中(本例中为CustomJwtSecurityTokenHandler)

public class CustomJwtSecurityTokenHandler : ISecurityTokenValidator {
   ...

   //Set IHttpContextAccessor as public property to set later in Starup class
   public IHttpContextAccessor _httpContextAccessor { get; set; };

   //Remove injection of httpContextAccessor;
   public CustomJwtSecurityTokenHandler()
   {
   _tokenHandler = new JwtSecurityTokenHandler();
   }

   ...

并在Startup类中将属性“CustomJwtSecurityTokenHandler”配置为全局成员

public readonly CustomJwtSecurityTokenHandler customJwtSecurityTokenHandler = new()

在Startup类的ConfigureServices方法中添加全局customJwtSecurityTokenHandler。

 public void ConfigureServices(IServiceCollection services)
 {

      ...

      services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
           .AddJwtBearer(
                o =>
                {
                    ...
                    //Add the global ISercurityTokenValidator implementation
                    o.SecurityTokenValidators.Add(this.customJwtSecurityTokenHandler );
                }
            );

      ...
} 

然后在启动类的配置方法中,将IHttpContextAccess实例传递给全局自定义JwtSecurityTokenHandler(ISecurityTokenValidator)的属性

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
         ILoggerFactory loggerFactory, IApplicationLifetime appLifetime,
         IServiceProvider serviceProvider)
{
    ...
    var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
    //And add to property, and not by constructor
    customJwtSecurityTokenHandler.httpContextAccessor = httpContextAccessor;
    ...
}

在我的例子中,我已经在ConfigureService中配置了SecurityTokenValidator,所以这一次不存在任何IServiceProvider的Instance,那么在Configure方法中,您可以使用IServiceProvider获取IHttpContextAccessor

艾照
2023-03-14

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

默认情况下,IHttpContextAccessor服务未注册,因此首先需要在启动中添加以下内容。配置服务方法:

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实例化。如果你对所有这些东西都不熟悉,请查看依赖注入文档。

更新:如何手动解决依赖关系(更多信息在这里)

修改配置方法以使用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);
    ...
}
 类似资料:
  • 这是自定义承载令牌授权机制的可接受实现吗? 授权属性 验证服务。APISettings类用于appSettings,但验证可以扩展为使用数据库。。。显然:) 实施 应用设置 } 请求头

  • 我正在尝试在ASP.NET5中实现OAuth承载令牌身份验证,并且正在努力寻找一个如何实现这一点的示例,因为OWIN的东西在ASP.NET5中发生了变化。 例如IApplicationBuilder.UseOAuthAuthorizationServer()和IApplicationBuilder。UseOAuthBearerAuthentication()要么不再存在,要么缺少引用? 如有任何指

  • 目前正在使用一个JWT身份验证模式,其中令牌在模式中有“Bearer:Bearer”。是否可以删除“Bearer:Bearer”前缀,这样我就不需要在客户端添加它,以便在后端再次解析它?有没有一种方法可以做到这一点,而无需实现自定义方案(因此仍然使用Bearer scheme),也无需解析“Bearer:Bearer:Bearer:的实际令牌“短信? 现在,代码如下所示: 理想情况下,它将按如下方

  • 我在令牌使用者上得到以下错误。任何帮助解决这将是非常感谢的。多谢了。 “IDX10503:签名验证失败。 公共无效配置(IApplicationBuilder应用程序)

  • 嗨,伙计们,我正在开发应用程序使用spring boot和spring security在我的应用程序中进行身份验证,我使用自定义令牌,并且我能够成功地对用户进行身份验证。现在我想添加自定义授权到我的应用程序我想通过以下方式进行授权: 我的自定义userDetails服务如下: