ASP.NET CoreでJWTベアラ認証を使用するアプリケーションを作成しました。認証するとき、アクションを実行するために別のWebAPIコントローラーで読み取る必要があるカスタムクレームを定義します。
どのようなアイデアを実現できますか?
これは私のコードがどのように見えるか:(コードが簡素化されています)
public async Task<IActionResult> AuthenticateAsync([FromBody] UserModel user)
{
..............
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim("userSecurityKey", userDeserialized.SecurityKey.ToString()),
new Claim("timeStamp",timeStamp),
new Claim("verificationKey",userDeserialized.VerificationKey.ToString())
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
.................
}
別のコントローラー:(「verificationKey」クレームを読み取る必要があります。)
[HttpGet]
[Route("getcandidate")]
public async Task<IActionResult> GetCandidateAsync()
{
try
{
............
var verificationKey = //TODO: GET VerificationKey FROM THE TOKEN
var verificationRecord = await service.GetVerificationRecordAsync(verificationKey);
.................
}
catch (Exception)
{
return NotFound();
}
}
コントローラ内でこのようなクレームを取得できるはずです
_var identity = HttpContext.User.Identity as ClaimsIdentity;
if (identity != null)
{
IEnumerable<Claim> claims = identity.Claims;
// or
identity.FindFirst("ClaimName").Value;
}
_
必要に応じて、IPrincipalインターフェイスの拡張メソッドを記述し、上記のコードを使用してクレームを取得してから、(たとえば)
_HttpContext.User.Identity.MethodName();
_
答えを完全にするため。 JWTトークンをデコードするには、トークンを検証して情報を抽出するメソッドを作成しましょう。
_public static ClaimsPrincipal ValidateToken(string jwtToken)
{
IdentityModelEventSource.ShowPII = true;
SecurityToken validatedToken;
TokenValidationParameters validationParameters = new TokenValidationParameters();
validationParameters.ValidateLifetime = true;
validationParameters.ValidAudience = _audience.ToLower();
validationParameters.ValidIssuer = _issuer.ToLower();
validationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Secret));
ClaimsPrincipal principal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);
return principal;
}
_
次を使用して、クレームを検証および抽出できます。
ValidateToken(tokenString)?.FindFirst("ClaimName")?.Value
ValidateTokenメソッドは、検証が失敗するとnull
値を返すことに注意してください。
// Cast to ClaimsIdentity.
var identity = HttpContext.User.Identity as ClaimsIdentity;
// Gets list of claims.
IEnumerable<Claim> claim = identity.Claims;
// Gets name from claims. Generally it's an email address.
var usernameClaim = claim
.Where(x => x.Type == ClaimTypes.Name)
.FirstOrDefault();
// Finds user.
var userName = await _userManager
.FindByNameAsync(usernameClaim.Value);
if (userName == null)
{
return BadRequest();
}
// The rest of your code goes here...
.NET FrameworkにはいくつかのJWT実装があります。 System.IdentityModel.Tokens.Jwtを使用する場合、トークンを検証すると、System.Securityが取得されます。 Claims.ClaimsPrincipalトークンのクレームを「Claims」プロパティに保存します。したがって、次のようにトークンのクレームを取得できます。
string token = // ... read the token
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = ...;
SecurityToken securityToken;
IPrincipal principal;
try
{
// token validation
principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
// Reading the "verificationKey" claim value:
var vk = principal.Claims.SingleOrDefault(c => c.Type == "verificationKey").Value;
}
catch
{
principal = null; // token validation error
}
このコードをどこに配置しますか?私の選択は、トークン検証をAuthorizationFilterAttributeから派生した承認フィルター属性として実装することでした。コントローラーを属性で装飾すると、そのOnAuthorizationメソッドは、コントローラーのエンドポイントへのすべての呼び出しの前に実行されます。上記のコードをOnAuthorizationメソッドに配置し、トークン検証で返されたプリンシパルをHttpContext.Current.Userに保存します。 APIのエンドポイント。 http://blogs.quovantis.com/json-web-token-jwt-with-web-api/ は、この実装の素晴らしいサンプルです。