4

I have trouble with understanding Roles in Identity Core

My AccountController looks like this, I added Roles in claims in GenerateJWTToken method:

[HttpPost("Login")]
    public async Task<object> Login([FromBody] LoginBindingModel model)
    {
        var result = await this.signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false);

        if (result.Succeeded)
        {
            var appUser = this.userManager.Users.SingleOrDefault(r => r.UserName == model.UserName);
            return await GenerateJwtToken(model.UserName, appUser);
        }

        throw new ApplicationException("INVALID_LOGIN_ATTEMPT");
    }

    [HttpPost("Register")]
    public async Task<object> Register([FromBody] RegistrationBindingModel model)
    {
        var user = new ApplicationUser
        {
            UserName = model.UserName,
            Email = model.Email,
            FirstName = model.FirstName,
            LastName = model.LastName
        };
        var result = await this.userManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            await this.signInManager.SignInAsync(user, false);
            return await this.GenerateJwtToken(model.UserName, user);
        }

        throw new ApplicationException("UNKNOWN_ERROR");
    }

    private async Task<object> GenerateJwtToken(string userName, IdentityUser user)
    {
        var claims = new List<Claim>
        {
            new Claim(JwtRegisteredClaimNames.Sub, userName),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(ClaimTypes.NameIdentifier, user.Id),
            new Claim(ClaimTypes.Role, Role.Viewer.ToString()),
            new Claim(ClaimTypes.Role, Role.Developer.ToString()),
            new Claim(ClaimTypes.Role, Role.Manager.ToString())
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.configuration["JwtKey"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var expires = DateTime.Now.AddDays(Convert.ToDouble(this.configuration["JwtExpireDays"]));

        var token = new JwtSecurityToken(
            this.configuration["JwtIssuer"],
            this.configuration["JwtIssuer"],
            claims,
            expires: expires,
            signingCredentials: creds);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }

From this code my token works perfectly with [Authorize] controller's attribute.

My question is, in which step add role to my registered user to use (for example) [Authorize("Admin")]? How to save role to database?

[Route("api/[controller]")]
[Authorize] //in this form it works ok, but how to add roles to it with JWT Token?
            //how to register user to role and get this role to JWT Token?
[ApiController]
public class DefaultController : ControllerBase

My ApplicationUser:

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

And Enum for Roles:

public enum Role
{
    Viewer,
    Developer,
    Manager
}

How to save information about user role to Identity Database and while login get that role to properly working [Authorize] attribute?

EDIT:

What i want to do is to store Roles like in my enums in User. I want to register user as Developer, Manager etc. I belive i can do it by ApplicationUser and add Role property, but from it i couldnt get authorization by attribute [Authorization(role)]

michasaucer
  • 4,562
  • 9
  • 40
  • 91

2 Answers2

3

You don't need to use IdentityUser and identity database in your case, you are using JWT. Create your User model with defined Roles property and simple persist it in the database. Like:

public class User
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public Role Role { get; set; }
}

public enum Role
{
   Viewer,
   Developer,
   Manager
}

the token:

var user = // ...
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(your_seccret_key);
var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(new Claim[] 
         {
             new Claim(ClaimTypes.Name, user.FirstName),
             new Claim(ClaimTypes.Name, user.LastName),
             new Claim(ClaimTypes.Role, user.Role)
         }),
     Expires = DateTime.UtcNow.AddDays(1),
     SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),SecurityAlgorithms.HmacSha256Signature)
 };
 var token = tokenHandler.CreateToken(tokenDescriptor);
 user.Token = tokenHandler.WriteToken(token);

controller method:

[Authorize(Roles = Role.Developer)]
[HttpGet("GetSomethingForAuthorizedOnly")]
public async Task<object> GetSomething()
{ 
   // .... todo
}
  • Maybe, but i want to use Identity to store users in roles. I cant find any solution for authorize users in Identity. I need to use JWT if i want to use tokens – michasaucer Apr 29 '19 at 10:22
  • There is no some big benefit of that. Create simple user model, add password to it as well, read password + add salt, than do the encryption, find safe algorithm, don't use md5 or sha1. Never decrypt the password, add try limit and you are prity safe. – Milenko Jevremovic Apr 29 '19 at 10:34
  • Suppose I don't use Identity, then how do I check for roles? For example - this link says .AddRoles -https://learn.microsoft.com/en-us/aspnet/core/security/authorization/secure-data?view=aspnetcore-6.0#add-role-services-to-identity - But since I don't use identity then do I still need this line? – variable Jan 10 '22 at 08:33
1

You could use the built-in Role Management with ASP.NET Identity . Since you are using ASP.NET Core 2.1 , you could firstly refer to below link for enable roles in identity system :

https://stackoverflow.com/a/54069826/5751404

After enabling roles , you can register roles/users , then adding roles to user like :

private async Task CreateUserRoles()
{   
    IdentityResult roleResult;
    //Adding Admin Role
    var roleCheck = await _roleManager.RoleExistsAsync("Admin");
    if (!roleCheck)
    {

        IdentityRole adminRole = new IdentityRole("Admin");
        //create the roles and seed them to the database
        roleResult = await _roleManager.CreateAsync(adminRole);

        _roleManager.AddClaimAsync(adminRole, new Claim(ClaimTypes.AuthorizationDecision, "edit.post")).Wait();
        _roleManager.AddClaimAsync(adminRole, new Claim(ClaimTypes.AuthorizationDecision, "delete.post")).Wait();

        ApplicationUser user = new ApplicationUser {
            UserName = "YourEmail", Email = "YourEmail",

        };
        _userManager.CreateAsync(user, "YourPassword").Wait();

        await _userManager.AddToRoleAsync(user, "Admin");
    }

}

So that when that user login into your application , you can find role claims in ClaimsPrincipal , and that works with Authorizeattribute with roles.

Nan Yu
  • 26,101
  • 9
  • 68
  • 148
  • In asp mvc yes, but what if i wan to use webapi? – michasaucer Apr 30 '19 at 04:36
  • In web api , directly use JWT token , or manually sign-in with role claim :https://stackoverflow.com/a/55645212/5751404 – Nan Yu Apr 30 '19 at 05:19
  • I still not fully understand your requirement , with JWT token pass to your web api , your web api side need to register user and role in ASP.NET Identity system ? – Nan Yu Apr 30 '19 at 05:20
  • I forget to mention that, my bad. My project is `webapi`, i need to have token to login into `webapi` services. Thats why i need something like `JWT`, to external login users from front end (`webapi` proj is my backend) – michasaucer Apr 30 '19 at 05:49
  • @michasaucer , then why not use JWT and use policy based authorization ? Or you can manually decode token and sign-in with role claim : https://stackoverflow.com/questions/55628357/asp-net-core-2-2-jwt-claims-identity-authentication-for-website/55645212#55645212 – Nan Yu Apr 30 '19 at 05:52