简体   繁体   中英

Get claims from a WebAPI Controller - JWT Token,

I have built an application which uses JWT bearer authentication in ASP.NET Core. When authenticating I define some custom claims which i need to read in another WebAPI controller in order to execute some actions.

Any ideas How Can I achieve this?

This how my code looks like:(Code has been simplified)

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);

     .................                           

    }

Another controller: (It Needs to read "verificationKey" claim.)

    [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();
        }
    }

You should be able to retrieve a claims like this within your controller

var identity = HttpContext.User.Identity as ClaimsIdentity;
if (identity != null)
{
    IEnumerable<Claim> claims = identity.Claims; 
    // or
    identity.FindFirst("ClaimName").Value;

}

If you wanted, you could write extension methods for the IPrincipal interface and retrieve claims using the code above, then retrieve them using (for example)

HttpContext.User.Identity.MethodName();

For completeness of the answer. To Decode the JWT token let's write a method to validate the token and extract the information.

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;
    }

Now we can validate and extract the Claims by using:

ValidateToken(tokenString)?.FindFirst("ClaimName")?.Value

You should note that the ValidateToken method will return null value if the validation fails.

In any controller from.net core 2 that has gone through the authorize with the JwtBearerDefaults scheme, you can use:

 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
 public ActionResult Index()
    {
        var user = User.FindFirst("Name").Value;
        //or if u want the list of claims
        var claims = User.Claims;

        return View();
    }

One way to decode JWT, and get claim is using System.IdentityModel.Tokens

public string getJWTTokenClaim(string token, string claimName)
{
    try
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var securityToken = (JwtSecurityToken)tokenHandler.ReadToken(token);
        var claimValue = securityToken.Claims.FirstOrDefault(c => c.Type == claimName)?.Value;
        return claimValue;
    }
    catch (Exception)
    {
        //TODO: Logger.Error
        return 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...

There are a few JWT implementations for .NET Framework. If you use System.IdentityModel.Tokens.Jwt , when you validate the token you get a System.Security.Claims.ClaimsPrincipal that stores the token's claims in its "Claims" property. So you can get the token's claims as follows:

        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
        }

Now where do you place this code? My choice was to implement the token validation as an authorization filter attribute derived from AuthorizationFilterAttribute . If you decorate a controller with the attribute, its OnAuthorization method is executed before every call to the controller's endpoints. You place the above code on the OnAuthorization method, and store the principal returned by the token validation on HttpContext.Current.User , that is also accessible on any endpoint on your API. http://blogs.quovantis.com/json-web-token-jwt-with-web-api/ is a nice sample of this implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM