ASP.Net中的JWT令牌异常(生命周期验证失败.令牌缺少过期时间.)

AHA*_*AHA 5 asp.net authentication authorization lifetime jwt

我在ASP上创建自己的自定义身份验证.Net Mobile部署在Azure上.我使用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;
    }
Run Code Online (Sandbox Code Playgroud)

令牌被发送到客户端并存储.但是当我尝试基于其令牌授权消息时,我收到错误:

终身验证失败.令牌缺少过期时间.

这是我尝试验证令牌的方式:

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

执行时抛出异常tokenHandler.ValidateToken并返回null principal.

我的假设是,我可能没有正确设置ExpiresIssuers属性,并且TokenHanlder无法验证它们.但是,当我检查jwtToken时,所有声明都已正确设置.

这是完整的调试输出:

JWTManager> GetPrincipal>声明:电子邮件:testEmail@email.com

JWTManager> GetPrincipal>声明:nbf:1494752301

JWTManager> GetPrincipal> Claims:exp:33051661101

JWTManager> GetPrincipal>声明:iat:1494752301

JWTManager> GetPrincipal>声明:iss:MASKED

JWTManager> GetPrincipal>声明:aud:MAKSED

JWTManager> GetPrincipal:IDX10225:生命周期验证失败.令牌缺少过期时间.应用:Tokentype:

Awa*_*Teh 13

@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它超过Microsoft的exp值的上限差不多80年:).

我希望微软能尽快解决这个问题,但是对于遇到类似问题的人来说,同时不要发出太长时间的令牌,或者至少不要让它超过Tue,2038年1月19日@ 03:14 :07 GMT :).


AHA*_*AHA 6

按照此处的建议,我通过从使用切换来解决了问题

System.IdentityModel.Tokens.Jwt.TokenHandler.CreateToken(SecurityTokenDescriptor)

new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(JwtHeader, JwtPayload)

并将有效负载定义如下:

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}
};
Run Code Online (Sandbox Code Playgroud)

因此,我最终没有使用 SecurityTokenDescriptor 类,因为它希望将 DateTime 对象分配给ExpirsIssuedAtLifetime属性(取决于它是否位于Microsoft.IdentityModel.TokensSystem.IdentityModel.Tokens命名空间中)。

我无意使用 SecurityTokenDescriptor;但是,我找不到有关如何使用 SecurityTokenDescriptor 的解决方案,并且仍然为“exp”字段设置正确的值。