我在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;
}
令牌被发送到客户端并存储。但是当我尝试基于其令牌授权消息时,我收到错误:
终身验证失败。令牌缺少过期时间。
这是我尝试验证令牌的方式:
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
。
我的假设是,我可能没有正确设置Expires
和Issuers
属性,并且TokenHanlder无法验证它们。但是,当我检查jwtToken时,所有声明都已正确设置。
这是完整的调试输出:
JWTManager> GetPrincipal>声明:电子邮件:[email protected]
JWTManager> GetPrincipal>声明:nbf:1494752301
JWTManager> GetPrincipal> Claims:exp:33051661101
JWTManager> GetPrincipal>声明:iat:1494752301
JWTManager> GetPrincipal>声明:iss:MASKED
JWTManager> GetPrincipal>索赔:aud:PAYMENTS
JWTManager> GetPrincipal:IDX10225:生命周期验证失败。令牌缺少过期时间。应用:Tokentype:
@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年:)。
我希望微软能尽快解决这个问题,但是对于遇到类似问题的人来说,同时不要发出太长时间的令牌,或者至少不要让它超过Tue,2038年1月19日@ 03:14 :07 GMT :)。
根据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
属性(取决于它是否在Microsoft.IdentityModel.Tokens
或System.IdentityModel.Tokens
命名空间中)。
我无意使用SecurityTokenDescriptor;但是,我找不到如何使用SecurityTokenDescriptor的解决方案,仍然将正确的值设置为“exp”字段。