我通过设置Payload创建了一个JwtToken,如下所示
var payload = new JwtPayload
{
{"aud", "wellmark.com" },
{"iss", "wellmark" },
{"iat", DateTime.Now.Ticks },
{"exp", DateTime.Now.AddDays(90).Ticks },
};
Run Code Online (Sandbox Code Playgroud)
我必须使用ticks的原因是因为这是获得发布时间和到期时间的整数值的唯一方法.我同意ticks实际上是一个很长的而不是int,但这是唯一的方法.
现在,当我回来验证令牌时,我正在执行以下操作
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<X509SecurityKey> { new X509SecurityKey(jwtCert) }
};
tokenHandler.ValidateToken(id, tokenValidationParams
, out validatedToken);
Run Code Online (Sandbox Code Playgroud)
然而,这是失败的说法
终身验证失败.令牌缺少过期时间.Tokentype:'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.
这很可能是因为验证方法试图长转换成int型,因为它无法将其转换,它只是返回一个空如图所示的文件中表示 这里.
有没有人在这个机制上取得成功.请注意,我使用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;
Run Code Online (Sandbox Code Playgroud)
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答案居然是技术上是正确的,它真的不解释为什么你得到了异常: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)开始的epcoh时间限制,任何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
以上两点要记住:
January 1, 0001
所有这些都表明,理论上这应该代表未来的某个时间点,尽管将来会超远.
其根本原因,为什么你实际上最终在你的SO票提到的异常实际上是不是你正在使用蜱(而不是一个时代的时间戳),而是因为微软对JWTs验证理论上限使用他们的框架时,和Owin中间件(稍后会详细介绍,继续阅读).
人们希望:
真的不应该施加这样的上限; 但也许有安全使用案例需要对门票的到期日施加上限 - 我现在无法想到一个.
尽管有上面的子弹#1,但是人们希望将来的上限真的很远(如果您既millennial
读了这个并且听说过/知道了Y2K的错误,那么额外的学分奖励积分?).然而,MS团队设定的限制实际上即将来临:January 19, 2038 @ 03:14:07 GMT
您可以尝试使用为2038年1月20日设置的exp值验证以下标记来自行测试(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"
}
Run Code Online (Sandbox Code Playgroud)
它没有通过验证验证
Microsoft.IdentityModel.Tokens.SecurityTokenException
和一个例外消息:IDX10225:生命周期验证失败.令牌缺少过期时间
这不是真的,我提供了一个到期日期,它是一个有效的纪元时间戳(而不是由DateTime.Ticks表示的一个非常大的数字;).
如果您重复相同的测试,通过尝试验证以下令牌,其exp值设置为2038年1月19日00:00:00(2147472000
) - 恰好在当前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"
}
Run Code Online (Sandbox Code Playgroud)
微软要么需要:
一个.延长令牌的到期值的最大日期
湾 或者,为exp值超过当前最大值时的情况添加另一个Exception消息 - 也许IDX10226: Liftetime validation not possible. Expiration date set too far in the future
.
好的,在经过这样的细节指出exp
索赔的上限之后,不能解释为什么开始有一个上限将是一种耻辱.有人读这篇文章已经发现了上限的原因,因为我已经删除了写入的线索; 如果您已经抓住了它,请告诉您,如果您还没有这里是原因:Microsoft 在对"exp"声明的声明纪元时间戳的值进行比较时隐式使用整数或(Int32)exp
.我想将此视为疏忽(有人可能没有完全考虑整个架构,也许没有考虑使用(显式或隐式)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进行转换.
最明显的一个是不创建在2147483647的纪元时间戳之后的任何时间点到期的令牌.在本文撰写的当前时间,微软的owin中间件无法验证(希望他们很快解决这个问题).
另一种解决方法是编写自己的令牌生命周期验证逻辑.它并不像人们想象的那么复杂,但它确实有助于理解底层的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)
归档时间: |
|
查看次数: |
4987 次 |
最近记录: |