ASPで独自のカスタム認証を作成しています。 AzureにデプロイされたNetMobileService。 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
の実行時に例外がスローされ、principal
にnullが返されます。
私の想定では、Expires
プロパティとIssuers
プロパティを正しく設定しておらず、TokenHanlderがそれらの検証に失敗している可能性があります。ただし、jwtTokenを確認すると、すべてのクレームが正しく設定されています。
完全なデバッグ出力は次のとおりです。
JWTManager> GetPrincipal>クレーム:eメール:[email protected]
JWTManager> GetPrincipal>クレーム:nbf:1494752301
JWTManager> GetPrincipal>クレーム:exp:33051661101
JWTManager> GetPrincipal>クレーム:iat:1494752301
JWTManager> GetPrincipal>クレーム:iss:MASKED
JWTManager> GetPrincipal>クレーム:aud:MAKSED
JWTManager> GetPrincipal:IDX10225:ライフタイム検証に失敗しました。トークンに有効期限がありません。アプリケーション:トークンタイプ:
提案に従って ここ 、使用から切り替えることで問題を修正しました
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}
};
そのため、DateTimeオブジェクトがExpirs
およびIssuedAt
、またはLifetime
プロパティに割り当てられることを想定しているため、SecurityTokenDescriptorクラスを使用しないことになりました(Microsoft.IdentityModel.Tokens
にあるかどうかによって異なります)またはSystem.IdentityModel.Tokens
名前空間)。
SecurityTokenDescriptorを使用するつもりはありません。ただし、SecurityTokenDescriptorを使用して、「exp」フィールドに正しい値を設定する方法についての解決策を見つけることができませんでした。
@aha、有効期限を1年先に短縮して問題を解決したようです。これは機能しますが、以前に失敗した根本的なアーキテクチャの理由を理解したい場合(そして、独自のコードで適切なアーキテクチャの変更を行う場合)、これを読むことができます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
ほぼ80年までのexp値のMicrosoftの上限:)。
マイクロソフトがこの問題をすぐに解決することを願っていますが、それまでの間、同様の問題が発生している場合は、長持ちするトークンを発行しないようにしてください。少なくとも、2038年1月19日火曜日@ 03:14を過ぎないようにしてください。 :07 GMT :)。