ASP.Net 中的 JWT 令牌異常(生命週期驗證失敗。令牌缺少過期時間。)
我正在 ASP 上創建自己的自定義身份驗證。部署在 Azure 上的 Net MobileService。我使用 JWT 令牌。這是我生成新令牌的方式(claimType = email):
public static string GetSecurityToken(String email) { var symmetricKey = Convert.FromBase64String(signingKey); var tokenHandler = new JwtSecurityTokenHandler(); var now = DateTime.UtcNow; var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Email, email) }), NotBefore = now, Expires = now.AddYears(10), Issuer = issuer, Audience = audience, IssuedAt = now, SigningCredentials = new SigningCredentials( new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature), }; var stoken = tokenHandler.CreateToken(tokenDescriptor); var token = tokenHandler.WriteToken(stoken); return token; }令牌被發送到客戶端並儲存。但是當我嘗試根據其令牌授權消息時,我收到錯誤消息:
終生驗證失敗。令牌缺少過期時間。
這就是我嘗試驗證令牌的方式:
public static ClaimsPrincipal GetPrincipal(string token) { try { var tokenHandler = new JwtSecurityTokenHandler(); var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken; if (jwtToken == null) return null; var symmetricKey = Convert.FromBase64String(signingKey); Debug.WriteLine(String.Format("JWTManager > GetPrincipal > Validating Token: {0}", token)); foreach (Claim claim in jwtToken.Claims) { Debug.WriteLine(String.Format("JWTManager > GetPrincipal > Claims: {0}", claim.ToString())); } var validationParameters = new TokenValidationParameters() { //RequireExpirationTime = true, //ValidateLifetime = true, ValidateIssuer = true, ValidateAudience = true, IssuerSigningKey = new SymmetricSecurityKey(symmetricKey), }; SecurityToken securityToken; var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken); if (principal != null) Debug.WriteLine(String.Format("JWTManager > GetPrincipal > Principal: {0}", principal)); return principal; } catch (SecurityTokenException ex) { Debug.WriteLine(String.Format("JWTManager > GetPrincipal: {0}", ex.Message)); return null; } catch (Exception ex) { Debug.WriteLine(String.Format("JWTManager > GetPrincipal: {0}", ex.Message)); return null; } }執行時拋出異常,
tokenHandler.ValidateToken返回 nullprincipal。我的假設是,也許我沒有正確設置
ExpiresandIssuers屬性,並且 TokenHanlder 無法驗證它們。但是,當我檢查 jwtToken 時,所有聲明都已正確設置。這是完整的調試輸出:
JWTManager > GetPrincipal > 聲明:電子郵件:testEmail@email.com
JWTManager > GetPrincipal > 聲明:nbf:1494752301
JWTManager > GetPrincipal > 聲明:exp:33051661101
JWTManager > GetPrincipal > 聲明:iat:1494752301
JWTManager > GetPrincipal > 聲明:ISS:MASKED
JWTManager> GetPrincipal> 聲明:aud: PAYMENTS
JWTManager > GetPrincipal:IDX10225:生命週期驗證失敗。令牌缺少過期時間。應用: 令牌類型:
按照這裡的建議,我通過從使用切換來解決問題
System.IdentityModel.Tokens.Jwt.TokenHandler.CreateToken(SecurityTokenDescriptor)到
new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(JwtHeader, JwtPayload).並將payload定義如下:
DateTime centuryBegin = new DateTime(1970, 1, 1); var exp = new TimeSpan(DateTime.Now.AddYears(1).Ticks - centuryBegin.Ticks).TotalSeconds; var now = new TimeSpan(DateTime.Now.Ticks - centuryBegin.Ticks).TotalSeconds; var payload = new System.IdentityModel.Tokens.Jwt.JwtPayload { {"iss", issuer}, {"aud", audience}, {"iat", (long)now}, {"exp", (long)exp} };因此,我最終沒有使用 SecurityTokenDescriptor 類,因為它希望將 DateTime 對象分配給
ExpirsandIssuedAt或Lifetime屬性(取決於它是否在Microsoft.IdentityModel.TokensorSystem.IdentityModel.Tokens命名空間中)。我無意使用 SecurityTokenDescriptor;但是,我找不到關於如何使用 SecurityTokenDescriptor 並且仍然為“exp”欄位設置正確值的解決方案。
@aha,看來您通過將到期日期時間縮短到未來一年來解決了您的問題。哪個有效,但是如果您想了解它之前失敗的底層架構原因(並因此在您自己的程式碼中進行適當的架構更改),您可以在此處閱讀此 SO 文章:https ://stackoverflow.com/a/ 46654832/1222775。
最重要的是,針對 Microsoft owin 中間件驗證的 JWT 的到期日期有一個上限
2147483647(也恰好是 Int32.MaxValue),這意味著:Tue, 19 Jan 2038 03:14:07 GMT在您的 SO 問題中,您發布的調試輸出顯示了您使用的“exp”聲明值,該值
33051661101轉換為:Wednesday, May 14, 3017 8:58:21 AM它超過了微軟的 exp 值上限近 80 年:)。我希望微軟能盡快解決這個問題,但與此同時,對於遇到類似問題的任何人,盡量不要發行太持久的令牌,或者至少不要讓它超過 2038 年 1 月 19 日星期二 @ 03:14 :07 GMT :)。