Asp.net

ASP.Net 中的 JWT 令牌異常(生命週期驗證失敗。令牌缺少過期時間。)

  • July 28, 2020

我正在 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返回 null principal

我的假設是,也許我沒有正確設置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 對象分配給ExpirsandIssuedAtLifetime屬性(取決於它是否在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 :)。

引用自:https://stackoverflow.com/questions/43962567