我通过设置Payload创建了一个JwtToken,如下所示
var payload = new JwtPayload
{
{"aud", "wellmark.com" },
{"iss", "wellmark" },
{"iat", DateTime.Now.Ticks },
{"exp", DateTime.Now.AddDays(90).Ticks },
};
我必须使用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);
然而,没有说
终身验证失败。令牌缺少过期时间。 Tokentype:'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'。
这很可能是因为验证方法试图将long转换为int并且因为它无法转换它,所以它只返回一个null,如显示here所示的文档所示。
有没有人在这个机制上取得成功。请注意,我使用X509证书签署我的Jwt。
拉辛哈
答案 0 :(得分:7)
您不能将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/或类似网站检查您的时间戳
答案 1 :(得分:7)
值得注意的另一点是,虽然@jps答案实际上在技术上是正确的,但它实际上并没有解释为什么你得到例外:Lifetime validation failed. The token is missing an Expiration Time. Tokentype: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'
;为什么它会暗示你错过了一个到期时间,即使你已经明确地提供了一个Int64(长)?从理论上讲,任何Int64数字都应代表未来的某个时间点,即使考虑到从January 1st 1970
(https://tools.ietf.org/html/rfc7519#section-2)开始的epcoh时间限制。
真正的潜在问题是,当您使用Ticks时使用的数字是一个非常大的数字;例如,Microsoft将其定义为:
自公元0001年1月1日午夜12:00:00(格林历年1月1日0:00:00,公历为https://msdn.microsoft.com/en-us/library/system.datetime.ticks(v=vs.110).aspx后,已经过的100纳秒间隔的数量。https://msdn.microsoft.com/en-us/library/system.int32.maxvalue(v=vs.110).aspx
上面要记住两件事:
January 1, 0001
所有这一切都说,理论上这应该代表未来的某个时间点,尽管将来会超远。
你实际上最终得到SO票据中提到的例外的根本原因实际上是 NOT 你正在使用Ticks(而不是纪元时间戳),而是因为微软有一个理论使用框架和Owin中间件时验证JWT的上限(以后更多,继续阅读)。
人们希望:
这样的上限真的不应该强加;但也许有安全使用案例需要对门票的到期日施加上限 - 我现在无法想到这一点。
上面的子弹#1尽管如此,人们希望将来的上限真的很远(如果你是millennial
读到这个并且听过/知道Y2K的bug?)。但是,MS团队设定的限制实际上就在附近:January 19, 2038 @ 03:14:07 GMT
您可以尝试使用为2038年1月20日(2147558400
)设置的exp值验证以下标记,从而自行测试。
{
"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"
}
使用
验证失败
Microsoft.IdentityModel.Tokens.SecurityTokenException
和异常消息:IDX10225:生命周期验证失败。令牌缺少过期时间
这不是真的,我提供了一个到期日期,它是一个有效的纪元时间戳(而不是由DateTime.Ticks表示的一个极其庞大的数字;)。
如果您重复相同的测试,尝试验证以下令牌,其exp值设置为2038年1月19日00:00:00(2147472000
) - 恰好在理论上的限制之前目前的January 19, 2038 @ 03:14:07 GMT
MSFT库,它的工作原理。
{
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "SampleToken",
"nbf": 1507578537,
"exp": 2147472000,
"iss": "https://api.example.com",
"aud": "https://example.com"
}
Microsoft要么:
一个。延长令牌的到期值的最长日期
湾或者,当exp值超过当前最大值时,为案例添加另一个Exception消息 - 也许IDX10226: Liftetime validation not possible. Expiration date set too far in the future
。
好的,在详细说明exp
声明的上限之后,如果不解释为什么会有一个上限,那将是一种耻辱。有人读这篇文章已经发现了上限的原因,因为我已经删除了写入的线索;如果你已经抓住了它,感谢你,如果你还没到这里,原因如下:
当对&#34; exp&#34;的exp
声明时间戳的值进行比较时,Microsoft使用整数或(Int32)隐式 隐式。要求。我想将此视为一种疏忽(有人可能没有完全考虑整个架构,也许没有考虑使用(显式或隐式)Int32与长数据类型(Int64)的含义存储/比较纪元时间戳。这让我觉得很愚蠢,这是一个真正的架构决定,选择Int32作为与他们的库的纪元时间戳交互的数据类型 - 但是再次,就像我之前在这篇文章中所说的那样,也许有安全使用案例需要这样一个强加的上限(我现在只能想到一个)。
仍然不相信,这是Int32可以容纳的最大值:2147483647,据微软称:https://www.epochconverter.com。假设2147483647是一个纪元时间戳,猜猜将2147483647转换为日期时你得到的GMT日期/时间是多少?你得到的是:2038年1月19日03:14:07 GMT。您可以使用http://www.niso.org/apps/group_public/download.php/14003/SP_Jones_JSON_isqv26no3.pdf方便转换。
最明显的一点就是不要创建在2147483647的纪元时间戳之后的任何时间点到期的令牌。它目前无法由微软的中间件验证写这篇文章(希望他们很快解决这个问题)。
另一种解决方法是编写自己的令牌生命周期验证逻辑。它并不像人们想象的那么复杂,但它确实有助于理解底层的Owin中间件和JW *(JWT,JWE,JWS,JWK等等.Michael B. Jones有一篇有趣的文章JW *在这里:{{3}})