C# JwtSecurityToken不';它不会在应该到期的时候到期

C# JwtSecurityToken不';它不会在应该到期的时候到期,c#,.net,jwt,C#,.net,Jwt,我目前正在System.IdentityModels.Tokens命名空间中使用JwtSecurityToken类。我使用以下命令创建令牌: DateTime expires = DateTime.UtcNow.AddSeconds(10); JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); var genericIdentity = new System.Security.Principal.GenericIden

我目前正在System.IdentityModels.Tokens命名空间中使用JwtSecurityToken类。我使用以下命令创建令牌:

DateTime expires = DateTime.UtcNow.AddSeconds(10);
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var genericIdentity = new System.Security.Principal.GenericIdentity(username, "TokenAuth");

ClaimsIdentity identity = new ClaimsIdentity(claims);
string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
var securityKey = new     InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
var signingCreds = new SigningCredentials(securityKey,     SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.HmacSha256Signature);
var securityToken = handler.CreateToken(
    issuer: issuer,
    audience: ConfigurationManager.AppSettings["UiUrl"].ToString(),
    signingCredentials: signingCreds,
    subject: identity,
    expires: expires,
    notBefore: DateTime.UtcNow
);
return handler.WriteToken(securityToken); 
出于某些原因,即使expires设置为当前时间后10秒,但在验证令牌时,直到大约5分钟,它实际上不会引发异常。看到这一点后,我想可能至少有5分钟的过期时间,所以我将过期时间设置为:

DateTime.UtcNow.AddMinutes(5);
DateTime.UtcNow.AddMinutes(-5).AddSecond(10);
然后它将在10分钟后过期,但异常消息表示过期时间已设置为预期时间(用户登录后5分钟),并且当它在异常中显示当前时间时,它是过期时间后5分钟。因此,它似乎知道它应该在什么时候过期,但实际上直到过期时间过后5分钟才抛出异常。然后,由于令牌似乎在我将其设置为过期的任何时间上增加了5分钟,因此我将过期时间设置为:

DateTime.UtcNow.AddMinutes(5);
DateTime.UtcNow.AddMinutes(-5).AddSecond(10);

我测试了这个,到目前为止它还没有过期(超过十分钟后)。有人能解释一下为什么会这样,我做错了什么吗?另外,如果您在我提供的代码中看到任何其他内容,我将非常感谢您的指导,因为我对使用JWTs和这个库还不熟悉。

我也刚刚实现了一个JWT令牌中间件,尽管internet上的示例使用了
UtcNow
,但我现在必须使用
,否则过期时间将关闭。当我现在使用
,有效期马上就到了

LifeTimeValidator似乎存在一些问题。您可以使用自定义委托覆盖其逻辑。另外,使用JwtBearerOptions类来控制身份验证中间件的行为。例如:

new JwtBearerOptions
{
     AutomaticAuthenticate = true,
     AutomaticChallenge = true,
     TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
     {
           ValidIssuer = _configuration["Tokens:Issuer"],
           ValidAudience = _configuration["Tokens:Audience"],
           ValidateIssuer = true,
           ValidateAudience = true,
           ValidateLifetime = true,
           LifetimeValidator = LifetimeValidator,
           ValidateIssuerSigningKey = true,
           IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Tokens:Key"]))
      }
}
并分配LifetimeValidotor委托,以提供其自己的超时验证逻辑:

private bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken token, TokenValidationParameters @params)
{
     if (expires != null)
     {
          return expires > DateTime.UtcNow;
     }
     return false;
}

在阅读了@Denis Kucherov的答案之后,我发现我可以使用他发布的同一个自定义验证器,而不必使用JWTBeareOptions类,这需要我添加一个新库

此外,由于有两个名称空间包含许多相同的类,我将确保提及所有这些都使用System.IdentityModels。。。名称空间。(不是Microsoft.IdentityModels…)

下面是我最终使用的代码:

private bool CustomLifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken tokenToValidate, TokenValidationParameters @param)
{
    if (expires != null)
    {
        return expires > DateTime.UtcNow;
    }
    return false;
}
private JwtSecurityToken ValidateJwtToken(string tokenString)
{
   string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
   var securityKey = new InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
   JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
   TokenValidationParameters validation = new TokenValidationParameters()
   {
       ValidAudience = "MyAudience",
       ValidIssuer = "MyIssuer",
       ValidateIssuer = true,
       ValidateLifetime = true,
       LifetimeValidator = CustomLifetimeValidator,
       RequireExpirationTime = true,
       IssuerSigningKey = securityKey,
       ValidateIssuerSigningKey = true,
   };
   SecurityToken token;
   ClaimsPrincipal principal = handler.ValidateToken(tokenString, validation, out token);
   return (JwtSecurityToken)token;
}

该问题与
ClockSkew
有关。通常,验证库(至少是MS库)会补偿时钟偏移<代码>时钟偏移
默认值为5分钟。看到答案了吗

您可以在
TokenValidationParameters
中更改
ClockSkew

var tokenValidationParameters = new TokenValidationParameters
{
    //...your setting

    // set ClockSkew is zero
    ClockSkew = TimeSpan.Zero
};

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = tokenValidationParameters
});

快乐编码

下面的链接给出确切答案,因为默认情况下MS的过期时间为5分钟。 所以,要么你要让它成为你的习惯,要么你要放弃的时间 过期:DateTime.Now.AddSeconds(30) 上述行中的30秒将添加到过期时间中。因此,总过期时间将为5分钟30秒

希望这会有所帮助。

.NET核心更新 这在.NET Core中的处理方式略有不同,因为
TokenValidationParameters
使用
ConfigureServices()
方法在
Startup.cs
中设置,然后由中间件自动处理

还请注意,MemorySymetricSecurityKey中较旧的
用于签名秘密以支持
SymmetricSecurityKey
,如下所示

public void配置服务(IServiceCollection服务)
{
// ...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(选项=>
{
options.TokenValidationParameters=新的TokenValidationParameters
{
validateisuer=true,
ValidateAudience=true,
ValidateLifetime=true,
ValidateSuersigningKey=true,
ValidisUser=\u config.AuthenticationSettings.TokenAuthority,
Validudience=\u config.AuthenticationSettings.TokenAuthority,
LifetimeValidator=令牌LifetimeValidator.Validate,
IssuerSigningKey=新对称安全密钥(
Encoding.UTF8.GetBytes(_config.AuthenticationSettings.SecurityKey))
};
});
// ...
}
因此,我还在@tkd_aj's中创建了自己版本的令牌验证器,并将其放入一个静态类中:

公共静态类TokenLifetimeValidator
{
公共静态bool验证(
日期时间?不是之前,
DateTime?过期,
SecurityToken TokenValidate,
TokenValidationParameters@param
) {
return(expires!=null&&expires>DateTime.UtcNow);
}
}

您是否正在使用Jwt库的5.0版本?或者您正在使用Asp.NETCore?我开始使用DateTime。现在我也遇到了同样的问题。不幸的是,我正在使用4.0库,因为我们一直在使用.NET4.5。Jwt库的5.0版本需要.NET4.6,所以我们不能使用它。@tkd_aj-ah。。。我用的是核心。我确实在使用UtcNow时遇到了休假问题,YMMV:)。啊,是的。我看到AspnetCore实际上有一个nuget包,你可以直接下载,它可以为你做中间件。。。不幸的是,这不适用于.NET4.5。不过,谢谢你的评论!JwtBearerOptions似乎需要另一个库。我在这里进行了检查:并尝试安装nuget。它每次都失败,即使我的项目在.NET4.5.1上。无法安装包“Microsoft.AspNet.Authentication.JwtBearer 1.0.0-beta8”。您正试图将此包安装到以“.NETFramework,Version=v4.5.1”为目标的项目中,但该包不包含任何与该框架兼容的程序集引用或内容文件知道为什么不让我安装吗?@tkd_aj-试试这个:那个是ASP.NET内核的。我们的项目使用ASP.NET4.5.1。我猜这是行不通的。@tkd_aj试试1.1.2版它应该可以在4.5.1和.NET Standart 1.4版的库instal上运行