asp.net-core.net-coreauthorizationclaims-based-identityclaims-authentication

Custom role based auth .NET CORE


I have a project in which users can have multiple roles, such as cashier and stock clerk. These roles have the same rights, however someone can also have the roles admin and cashier. In this case he can access more features than a admin/cashier on its own.

I've searched far and wide but I don't get any wiser from the documentation, as I first thought policies were the way to go, but now I think we need claim-based authorization.

After searching and playing around I found no answers on the following questions:

  1. What tables/entities do I need?
  2. Can this be done without scaffolding tools?
  3. How does this whole process work, how does .NET CORE know what roles to look at? How can I use custom roles?

If someone could help me out with this I would appreciate it.

Cheers.


Solution

  • One way is to use Identity and authorize the user by using [Authorize(Roles ="Admin")].

    If you want to do without scaffolding tools,you could use jwt token authentication or cookie authentication.

    Here is a simple demo about how to use cookie authentication:

    Model:

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
        public List<UserRole> UserRoles { get; set; }
    }
    public class Role
    {
        public int Id { get; set; }
        public string RoleName { get; set; }
        public List<UserRole> UserRoles { get; set; }
    }
    public class UserRole
    {
        public int UserId { get; set; }
        public User User { get; set; }
        public int RoleId { get; set; }
        public Role Role { get; set; }
    }
    public class LoginModel
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
    

    Controller:

    public class HomeController : Controller
    {
        private readonly YouDbContext _context;
    
        public HomeController(YouDbContext context)
        {
            _context = context;
        }
        public IActionResult Login()
        {
            return View();
        }
        [HttpPost]
        public async Task<IActionResult> Login(LoginModel model)
        {
            var claims = new List<Claim>{};
            var user = _context.User
                               .Include(u=>u.UserRoles)
                               .ThenInclude(ur=>ur.Role)
                               .Where(m => m.Name == model.Name).FirstOrDefault();
            if(user.Password==model.Password)
            {
                foreach(var role in user.UserRoles.Select(a=>a.Role.RoleName))
                {
                    var claim = new Claim(ClaimTypes.Role, role);
                    claims.Add(claim);
                }               
                var claimsIdentity = new ClaimsIdentity(
                    claims, CookieAuthenticationDefaults.AuthenticationScheme);
    
                var authProperties = new AuthenticationProperties{};
                await HttpContext.SignInAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    new ClaimsPrincipal(claimsIdentity),
                    authProperties);
            }
            return View("Index");
        }       
        public IActionResult Index()
        {
            return View();
        }
    
        //allow Cashier
        [Authorize(Roles = "Cashier")]
        public IActionResult Privacy()
        {
            return View();
        }
    
        //allow Admin
        [Authorize(Roles = "Admin")]
        public IActionResult AllowAdmin()
        {
            return View();
        }
    
        //allow both of the Admin and Cashier
        [Authorize(Roles = "Admin,Cashier")]
        public IActionResult AllowBoth()
        {
            return View();
        }
    
        //user has no rights to access the page
        public IActionResult AccessDenied()
        {
            return View();
        }
    
        //log out
        public async Task<IActionResult> Logout()
        {
            await HttpContext.SignOutAsync(
    CookieAuthenticationDefaults.AuthenticationScheme);
            return RedirectToAction("Index");
        }        
    }
    

    DbContext:

    public class YouDbContext: DbContext
    {
        public YouDbContext(DbContextOptions<YouDbContext> options)
            : base(options)
        {
        }
    
        public DbSet<User> User { get; set; }
        public DbSet<Role> Role { get; set; }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<UserRole>()
       .HasKey(bc => new { bc.UserId, bc.RoleId });
            modelBuilder.Entity<UserRole>()
                .HasOne(bc => bc.User)
                .WithMany(b => b.UserRoles)
                .HasForeignKey(bc => bc.UserId);
            modelBuilder.Entity<UserRole>()
                .HasOne(bc => bc.Role)
                .WithMany(c => c.UserRoles)
                .HasForeignKey(bc => bc.RoleId);
        }
    }
    

    Startup.cs:

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public IConfiguration Configuration { get; }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                    .AddCookie(options =>
                    {
                        options.LoginPath = "/Home/Login";
                        options.AccessDeniedPath = "/Home/AccessDenied";
                    });
            services.AddDbContext<WebApplication1Context>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("WebApplication1Context")));
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseHttpsRedirection();
            app.UseStaticFiles();
    
            app.UseRouting();
    
            app.UseAuthentication();
            app.UseAuthorization();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
    

    Result:

    enter image description here