Reputation: 2748
I have ASP.NET Core 2 configured to use JWT Tokens to authenticate. The configuration looks like this:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
};
});
Then I created a method where a user signs in which looks like this:
[AllowAnonymous]
[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] LoginViewModel model)
{
if (!ModelState.IsValid) return BadRequest("Could not create token");
var user = await _userManager.FindByNameAsync(model.UserName);
if (user == null) return BadRequest("Could not create token");
var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
if (!result.Succeeded) return BadRequest("Could not create token");
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Tokens:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var roles = await _userManager.GetRolesAsync(user);
var token = new JwtSecurityToken(_configuration["Tokens:Issuer"],
_configuration["Tokens:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return Ok(new {
access_token = new JwtSecurityTokenHandler().WriteToken(token),
roles });
}
}
I save the token and use it in my request. I have a very simple api endpoint:
[HttpGet("users")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult GetUsers()
{
var isInRole = HttpContext.User.IsInRole(Roles.Administrator);
return Ok(_service.GetAllUsers());
}
Here I get in the method, but isInRole
is always false. Even though my var roles = await _userManager.GetRolesAsync(user);
returns a list of roles including Administrator. Why does this not work then?
Upvotes: 3
Views: 1875
Reputation: 3627
public async Task<string> GenerateEncodedToken(string userName, string email, List<string> roles, ClaimsIdentity identity)
{
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.UniqueName, userName),
new Claim(JwtRegisteredClaimNames.Email, email),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64)
};
var id = identity.FindFirst(Constants.Strings.JwtClaimIdentifiers.Id);
claims.Add(id);
roles.ForEach(role =>
{
claims.Add(new Claim(ClaimTypes.Role, role));
});
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
Upvotes: 0
Reputation: 142
You need to add the Role claim into your claims
array like so
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
//role claim
new Claim(ClaimTypes.Role, "Administrator")
};
This is what Asp.Net will look at in the [Authorize(Roles="Administrator")]
attribute and HttpContext.User.IsInRole("Administrator");
Similarly ClaimTypes.Name
is used to produce User.Identity.Name
in your controller
I suggest you read the excellent article by Rui Figueiredo Secure a Web Api in ASP.NET Core on the subject
Upvotes: 7