简体   繁体   中英

Role based authorization in asp core 2 with jwt tokens and identity

I have tried some authorization examples in asp core 2 wiht jwt tokens and asp core identity. I have followed this code https://github.com/SunilAnthony/SimpleSecureAPI and it works fine.

The problem is role based authorization. I tried something like this: http://www.jerriepelser.com/blog/using-roles-with-the-jwt-middleware/

and the result is strange. My controller method:

[HttpGet]
[Authorize]
public IActionResult Get()
{
    IEnumerable<Claim> claims = User.Claims; // contains claim with Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" and Value = "Administrator"
    bool role = User.IsInRole("Administrator"); // true
    bool claim = User.HasClaim(ClaimTypes.Role, "Administrator"); // true

    return Ok(claims);
} 

When I call this endpoint just with attribute [Authorize] and check role / claims in code for current user it seems good (both checks are true), but when I have changed my authorization attribute to [Authorize(Roles = "Administrator")] it does not work -> when I call this endpoint with this attribute I will receive 404 . I don't know where is the problem. My startup class is completely same as in the git link above and I have just added list of string role names in the payload of access_token within then "roles" array:

It is hardcoded but I have changed my login method just for test like this:

[HttpPost("login")]
public async Task<IActionResult> SignIn([FromBody] Credentials Credentials)
{
    if (ModelState.IsValid)
    {
        var result = await _signInManager.PasswordSignInAsync(Credentials.Email, Credentials.Password, false, false);
        if (result.Succeeded)
        {
            IdentityUser user = await _userManager.FindByEmailAsync(Credentials.Email);

            List<string> roles = new List<string>();
            roles.Add("Administrator");

            return new JsonResult(new Dictionary<string, object>
                {
                    { "access_token", GetAccessToken(Credentials.Email, roles) },
                    { "username", user.Email },
                    { "expired_on", DateTime.UtcNow.AddMinutes(_tokenLength) },
                    { "id_token", GetIdToken(user) }
                });
        }
        return new JsonResult("Unable to sign in") { StatusCode = 401 };
    }
    return new JsonResult("Unable to sign in") { StatusCode = 401 };
}

And the GetAccessTokenMethod :

private string GetAccessToken(string Email, List<string> roles)
{
  var payload = new Dictionary<string, object>
  {
    { "sub", Email },
    { "email", Email },
    { "roles", roles },
  };
  return GetToken(payload);
}

Where is the problem with the [Authorize(Roles = "Administrator")] attribute?

The problem is with the claim's type:

http://schemas.microsoft.com/ws/2008/06/identity/claims/role

Somehow, the [Authorize] attribute fails to work when used with Roles value. So this [Authorize(Roles = "Administartor")] doesn't work. You have to map the claim type to only role by applying transformation on Startup class.

If you have an Owin based project:

app.UseClaimsTransformation(incoming =>
            {
                // either add claims to incoming, or create new principal
                var appPrincipal = new ClaimsPrincipal(incoming);
                if (appPrincipal.HasClaim(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"))
                {
                    var value = appPrincipal.Claims.First(x =>
                        x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").Value;

                    incoming.Identities.First().AddClaim(new Claim("role", value));
                }                

                return Task.FromResult(appPrincipal);
            });

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