JWTvalidation失败

我通过设置Payload创建了一个JwtToken,如下所示

var payload = new JwtPayload { {"aud", "wellmark.com" }, {"iss", "wellmark" }, {"iat", DateTime.Now.Ticks }, {"exp", DateTime.Now.AddDays(90).Ticks }, }; 

我必须使用ticks的原因是因为这是获得发布时间和到期时间的整数值的唯一方法。 我同意ticks实际上是一个很长的而不是int,但这是唯一的方法。

现在,当我回来validation令牌时,我正在执行以下操作

 var tokenValidationParams = new TokenValidationParameters { IssuerSigningKey = new X509SecurityKey(jwtCert), ValidAudience = "masked", ValidIssuer = "masked", IssuerSigningKeyResolver = (string token, Microsoft.IdentityModel.Tokens.SecurityToken securityToken, string kid, TokenValidationParameters validationParameters) => new List { new X509SecurityKey(jwtCert) } }; tokenHandler.ValidateToken(id, tokenValidationParams , out validatedToken); 

然而,这是失败的说法

终身validation失败。 令牌缺少过期时间。 Tokentype:’System.IdentityModel.Tokens.Jwt.JwtSecurityToken’。

这很可能是因为validation方法试图将long转换为int并且因为它无法转换它,所以它只返回一个null,如此处所示的文档中所示。

有没有人在这个机制上取得成功。 请注意,我使用X509证书签署我的Jwt。

拉辛哈

您不能将Ticks用于exp时间戳

JWT中的时间戳是UNIX时间戳,从01.01.1970 00:00 UTC开始计算: https : //tools.ietf.org/html/rfc7519#section-4.1.4解释了数字日期用于exp声明(以及对于nbf(不是之前)和iat(发布于)索赔)

https://tools.ietf.org/html/rfc7519#section-2定义数字日期:

一个JSON数值,表示从1970-01-01T00:00:00Z UTC到指定的UTC日期/时间的秒数,忽略闰秒。

如果您像在示例中那样直接创建有效负载,则需要计算自1.1.1970 UTC以来的秒数,例如:

 DateTime centuryBegin = new DateTime(1970, 1, 1); var exp = new TimeSpan(DateTime.Now.AddDays(90).Ticks - centuryBegin.Ticks).TotalSeconds; 

exp是从现在开始的90天。 当然,您也可以使用任何其他Add …方法来计算实验时间。 请参阅https://msdn.microsoft.com/de-de/library/system.datetimeoffset(v=vs.110).aspx以查看其他添加方法。

一些框架(例如System.IdentityModel.Tokens.Jwt)提供了创建令牌的函数,这些令牌接受DateTimeOffset类型的参数,这更容易处理。

使用http://www.unixtimestamp.com/或类似网站检查您的时间戳

值得注意的另一点是,虽然@jps答案实际上在技术上是正确的,但它实际上并不能解释为什么会出现exception: Lifetime validation failed. The token is missing an Expiration Time. Tokentype: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' Lifetime validation failed. The token is missing an Expiration Time. Tokentype: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' Lifetime validation failed. The token is missing an Expiration Time. Tokentype: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' ; 为什么它会暗示你错过了一个到期时间,即使你已经明确地提供了一个Int64(长)? 从理论上讲,即使考虑到从January 1st 1970开始的时间限制( https://tools.ietf.org/html/rfc7519#section-2 ),任何Int64号码都应代表未来的某个时间点。

真正的潜在问题是,当您使用Ticks时使用的数字是一个非常大的数字; 首先,微软将其定义为:

自公元0001年1月1日午夜12:00:00(格林夫日历0001年1月1日0:00:00)以来经过的100纳秒间隔的数量.https://msdn.microsoft.com/ EN-US /库/ system.datetime.ticks(v = vs.110)的.aspx

以上两点要记住:

  1. 它一直追溯到January 1, 0001
  2. 它基于Nano秒,纪元时间基于毫秒(因子为1000000)。

所有这一切都表明,理论上这应该代表未来的某个时间点,尽管将来会超级遥远。

那么为什么它不起作用 – 什么时候真的应该!

您实际上最终得到SO票证中提到的exception的根本原因实际上并不是您使用Ticks(而不是纪元时间戳),而是因为Microsoft在使用其框架时validationJWT具有理论上限和Owin中间件( 稍后会详细介绍,继续阅读)

人们希望:

  1. 真的不应该施加这样的上限; 但也许有安全使用案例需要对门票的到期日施加这样的上限 – 我现在真的想不到一个。

  2. 尽管有上面的子弹#1,但是人们希望将来的上限确实很远(如果你是millennial阅读并且已经听说过/知道Y2K的错误,那么额外的学分奖励积分?)。 然而,MS团队设定的限制实际上即将到来: January 19, 2038 @ 03:14:07 GMT

您可以尝试使用为2038年1月20日( 2147558400 )设置的exp值validation以下标记2147558400

 { "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "SampleToken", "nbf": 1507578537, "exp": 2147558400, //<== This timestamp will not work :/ "iss": "https://api.example.com", "aud": "https://example.com" } 

它没有通过validationvalidation

Microsoft.IdentityModel.Tokens.SecurityTokenException和exception消息:IDX10225:生命周期validation失败。 令牌缺少过期时间

这不是真的,我提供了一个到期日期,它是一个有效的纪元时间戳(而不是由DateTime.Ticks表示的一个非常大的数字;)。

如果您重复相同的测试,尝试validation以下令牌,其exp值设置为2038年1月19日00:00:00( 2147472000 ) - 这恰好在January 19, 2038 @ 03:14:07 GMT当前MSFT库的理论限制之前January 19, 2038 @ 03:14:07 GMT ,它有效。

 { "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "SampleToken", "nbf": 1507578537, "exp": 2147472000, "iss": "https://api.example.com", "aud": "https://example.com" } 

结论:

  1. 微软要么需要:

    一个。 延长令牌的到期值的最大日期

    湾 或者,当exp值超过当前最大值时添加另一个exception消息 - 也许IDX10226: Liftetime validation not possible. Expiration date set too far in the future IDX10226: Liftetime validation not possible. Expiration date set too far in the future

奖励点

好的,在经过这样的细节指出exp索赔的上限之后,不能解释为什么开始有一个上限将是一种耻辱。 有人读这篇文章已经发现了上限的原因,因为我已经删除了整篇文章中的线索; 如果你已经抓住了它,感谢你,如果你还没有这里是为什么:Microsoft在对“exp”声明的exp声明纪元时间戳的值进行比较时隐式使用整数或(Int32) 。 我想将此视为疏忽(有人可能没有完全考虑整个架构,也许没有考虑使用(显式或隐式)Int32与长数据类型(Int64)来存储/比较的含义epoch timestamps。这让我感到愚蠢,这是一个真正的架构决策,选择Int32作为与他们的库的纪元时间戳交互的数据类型 - 但是再次,就像我之前在这篇文章中所说的那样,也许有安全性用例需要这样一个强加的上限(我不能为我的生活现在想到一个)。

仍然不相信,这是Int32可以容纳的最大值:2147483647,根据微软的说法: https ://msdn.microsoft.com/en-us/library/system.int32.maxvalue( v = vs.110).aspx 。 假设2147483647是一个纪元时间戳,猜猜将2147483647转换为日期时你得到的GMT日期/时间是多少? 你得到的是:2038年1月19日03:14:07 GMT。 您可以使用https://www.epochconverter.com进行转换。

解决方法

  1. 最明显的一个是不要创建在2147483647的纪元时间戳之后的任何时间点到期的令牌。在撰写本文时,微软的owin中间件无法validation(希望他们很快解决这个问题)。

  2. 另一种解决方法是编写自己的令牌生命周期validation逻辑。 它并不像人们想象的那么复杂,但它确实有助于理解底层的Owin中间件和JW *(JWT,JWE,JWS,JWK等等.Michael B. Jones有一篇有趣的文章JW *在这里: http : //www.niso.org/apps/group_public/download.php/14003/SP_Jones_JSON_isqv26no3.pdf )