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

时间:2017-05-14 09:53:39

标签: asp.net authentication authorization jwt lifetime

我在ASP上创建自己的自定义身份验证。 Net Mobile部署在Azure上。我使用JWT令牌。以下是我生成新令牌的方法(claimType = email):

{% regroup cities by country as country_list %}

<ul>
    <li>Japan
    {% for country in country_list %}
        {% if country.grouper == "Japan" %}
            <ul>
            {% for city in country.list %}
                <li>{{ city.name }}: {{ city.population }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    {% endfor %}
    </li>
    <li>USA
    {% for country in country_list %}
        {% if country.grouper == "USA" %}
            <ul>
            {% for city in country.list %}
                <li>{{ city.name }}: {{ city.population }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    {% endfor %}
    </li>
    <li>Australia
    {% for country in country_list %}
        {% if country.grouper == "Australia" %}
            <ul>
            {% for city in country.list %}
                <li>{{ city.name }}: {{ city.population }}</li>
            {% endfor %}
            </ul>
        {% endif %}
    {% endfor %}
    </li>
</ul>

令牌被发送到客户端并存储。但是当我尝试根据其令牌授权邮件时,我收到错误:

  

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

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

    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; } } 时抛出异常,并将null返回tokenHandler.ValidateToken

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

以下是完整的调试输出:

  

JWTManager&gt; GetPrincipal&gt;声明:电子邮件:testEmail@email.com

     

JWTManager&gt; GetPrincipal&gt;索赔:nbf:1494752301

     

JWTManager&gt; GetPrincipal&gt;索赔:exp:33051661101

     

JWTManager&gt; GetPrincipal&gt;声明:iat:1494752301

     

JWTManager&gt; GetPrincipal&gt;声明:iss:MASKED

     

JWTManager&gt; GetPrincipal&gt;声明:aud:MAKSED

     

JWTManager&gt; GetPrincipal:IDX10225:终身验证失败。令牌缺少过期时间。应用:Tokentype:

2 个答案:

答案 0 :(得分:11)

@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:)。

答案 1 :(得分:3)

根据建议here,我通过切换使用

解决了问题

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}
};

所以,我最终没有使用SecurityTokenDescriptor类,因为它希望将DateTime对象分配给ExpirsIssuedAtLifetime属性(取决于它是否在{ {1}}或Microsoft.IdentityModel.Tokens命名空间)。

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