J'ai construit une application qui utilise l'authentification au porteur JWT dans ASP.NET Core. Lors de l'authentification, je définis certaines revendications personnalisées que je dois lire dans un autre contrôleur WebAPI afin d'exécuter certaines actions.
Des idées Comment puis-je y parvenir?
Voici à quoi ressemble mon code: (Le code a été simplifié)
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);
.................
}
Un autre contrôleur: (Il doit lire la revendication "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();
}
}
Vous devriez pouvoir récupérer une réclamation comme celle-ci dans votre contrôleur
var identity = HttpContext.User.Identity as ClaimsIdentity;
if (identity != null)
{
IEnumerable<Claim> claims = identity.Claims;
// or
identity.FindFirst("ClaimName").Value;
}
Si vous le souhaitez, vous pouvez écrire des méthodes d'extension pour l'interface IPrincipal et récupérer des revendications à l'aide du code ci-dessus, puis les récupérer à l'aide (par exemple)
HttpContext.User.Identity.MethodName();
Pour l'exhaustivité de la réponse. Pour décoder le jeton JWT, écrivons une méthode pour valider le jeton et extraire les informations.
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;
}
Nous pouvons maintenant valider et extraire les revendications en utilisant:
ValidateToken(tokenString)?.FindFirst("ClaimName")?.Value
Vous devez noter que la méthode ValidateToken renverra la valeur null
si la validation échoue.
// 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...
Il existe quelques implémentations JWT pour .NET Framework. Si vous utilisez System.IdentityModel.Tokens.Jwt , lorsque vous validez le jeton, vous obtenez un System.Security. Claims.ClaimsPrincipal qui stocke les revendications du jeton dans sa propriété "Claims". Vous pouvez donc obtenir les revendications du jeton comme suit:
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
}
Maintenant, où placez-vous ce code? Mon choix a été d'implémenter la validation du jeton en tant qu'attribut de filtre d'autorisation dérivé de AuthorizationFilterAttribute . Si vous décorez un contrôleur avec l'attribut, sa méthode OnAuthorization est exécutée avant chaque appel aux points de terminaison du contrôleur. Vous placez le code ci-dessus sur la méthode OnAuthorization et stockez le principal retourné par la validation du jeton sur HttpContext.Current.User , qui est également accessible sur n'importe quel point de terminaison sur votre API. http://blogs.quovantis.com/json-web-token-jwt-with-web-api/ est un bel exemple de cette implémentation.