Reputation: 39
I have the application which has authentication and authorization with JWT
token. I am using ASP.NET Core Identity
for registering users. So my goal is to have two roles: manager and user. I have created "RoleController"
that has CRUD
operations and I successfully added these roles but next step is to attach these roles to users and my question starts from here...
What is the best practice to achieve this? I mean should I send "Role"
field value when I register a new user? But in case like this, anyone can register as an manager. I thought to create different registration endpoints for Managers and Users but I don't know if it is best practice or not. So what can I do, how can I manage this role-based authentication and how can I register user with defined roles?
Upvotes: 2
Views: 3901
Reputation: 39
I decide to achieve this goal in this way:
Simply, I created "RoleController" as you can see below:
using AutoMapper;
using Contracts.ViewModels;
using Domain.Entities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace WOB.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Roles = "Admin, Manager")]
public class RoleController : ControllerBase
{
private readonly RoleManager<IdentityRole>? _roleManager;
private readonly UserManager<User>? _userManager;
private readonly IConfiguration? Configuration;
private readonly IMapper? _mapper;
public RoleController(
RoleManager<IdentityRole>? roleManager,
UserManager<User> userManager,
IMapper mapper,
IConfiguration? configuration)
{
_roleManager = roleManager;
_userManager = userManager;
_mapper = mapper;
Configuration = configuration;
}
[AllowAnonymous]
[HttpGet]
public async Task<IActionResult> GetAllRoles(CancellationToken cancellationToken = default)
{
var roles = await _roleManager.Roles.ToListAsync(cancellationToken);
if(roles == null)
{
return BadRequest("Unable to get roles.");
}
return Ok(roles);
}
[AllowAnonymous]
[HttpGet("{roleId}")]
public async Task<IActionResult> GetRoleById(string? roleId)
{
var role = await _roleManager.FindByIdAsync(roleId);
if(role == null)
{
return BadRequest("Unable to get the role.");
}
return Ok(role);
}
[HttpPost("[action]")]
public async Task<IActionResult> CreateCustomRole([FromBody] RoleModel? roleModel)
{
if(roleModel == null)
{
return BadRequest($"{nameof(roleModel)} cannot be null.");
}
var role = _mapper.Map<IdentityRole>(roleModel);
IdentityResult result = await _roleManager.CreateAsync(role);
if (!result.Succeeded)
{
return BadRequest("Unable to create a role.");
}
return Ok();
}
[AllowAnonymous]
[HttpPost]
// These controller create roles and them users in advance
public async Task<IActionResult> CreateRolesAndUsers()
{
// Checking if admin role already exists
bool exists = await _roleManager.RoleExistsAsync("Admin");
if (!exists)
{
// First we are creating Admin role
var role = new IdentityRole();
role.Name = "Admin";
await _roleManager.CreateAsync(role);
// Then we are creating User that will have a Admin role
var user = new User();
string email = Configuration["AdminSettings:Email"];
string password = Configuration["AdminSettings:Password"];
user.UserName = user.Email = email;
user.PasswordHash = _userManager.PasswordHasher.HashPassword(user, password);
IdentityResult result = await _userManager.CreateAsync(user, password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, role.Name);
}else
{
return BadRequest("Unable to create a Admin role.");
}
}
// Checking if Manager role already exists
exists = await _roleManager.RoleExistsAsync("Manager");
if (!exists)
{
// First we are creating Manager role
var role = new IdentityRole();
role.Name = "Manager";
await _roleManager.CreateAsync(role);
// Then we are creating User that will have a Manager role
var user = new User();
string email = Configuration["ManagerSettings:Email"];
string password = Configuration["ManagerSettings:Password"];
user.UserName = user.Email = email;
user.PasswordHash = _userManager.PasswordHasher.HashPassword(user, password);
IdentityResult result = await _userManager.CreateAsync(user, password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, role.Name);
}else
{
return BadRequest("Unable to create a Manager role.");
}
}
// Checking if Manager role already exists
exists = await _roleManager.RoleExistsAsync("User");
if (!exists)
{
// First we are creating Manager role
var role = new IdentityRole();
role.Name = "User";
IdentityResult result = await _roleManager.CreateAsync(role);
if (!result.Succeeded)
{
return BadRequest("Unable to create a User role.");
}
}
return Ok();
}
[HttpDelete("{roleId}")]
public async Task<IActionResult> DeleteRole(string? roleId)
{
if (string.IsNullOrEmpty(roleId))
{
return BadRequest($"{nameof(roleId)} cannot be null or empty.");
}
var role = await _roleManager.FindByIdAsync(roleId);
IdentityResult result = await _roleManager.DeleteAsync(role);
if (!result.Succeeded)
{
return BadRequest("Unable to delete the role.");
}
return Ok();
}
}
}
As you can see, I have created method "CreateRolesAndUsers" in which I have pre-defined: Admin, Manager and User roles creation. There is one problem about it and i will talk about it later.
Main logic of this method is to check if particular roles already exist, if not then create them and also create users that are relevant to them. Emails and Passwords for Admin and Manager roles are pre-defined in appsettings.json and without problem i am creating roles and their users.
Also i have created another method to create a custom roles.
One problem about this solution is next: When the application runs, you have to manually call this endpoint to add these roles into database. I don't know if it is possible to automatically call this method when an app builds and add these roles instantly in the database without manually calling it.
It could be the worst solution but at this time, it was the idea that i could thought of and most importantly, it does its job
Upvotes: 0
Reputation: 9943
This is a very good question. In Generally, high-privileged accounts are provided by companies or organizations rather than registered by themselves. In my opinion, a simple way to achieve this is that when the user is successfully registered, you can provide an email address for users who want to be Managers to send applications, Then you can determine whether this user can become a Managers by this application. If you think this user can become Manager, You can add role by yourself, If not, Just do nothing.
Upvotes: 0
Reputation: 681
You can use Identity UserManager to assign roles/custom roles for Users.
For example: await UserManager.AddToRoleAsync(poweruser, "Admin");
Following this, you can also assign roles to users during SignUp/Registration so that after account creation, the person will have those roles. You can also create custom roles and save those in DB and map those while user registration.
For conjugated role/permission you can try Identity Policies too.
Upvotes: 2