我在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
。
我的假设是,我可能没有正确设置principal
和Expires
属性,并且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:
答案 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对象分配给Expirs
和IssuedAt
或Lifetime
属性(取决于它是否在{ {1}}或Microsoft.IdentityModel.Tokens
命名空间)。
我无意使用SecurityTokenDescriptor;但是,我找不到如何使用SecurityTokenDescriptor的解决方案,仍然将正确的值设置为“exp”字段。