When building secure web applications, authentication tells you who the user is, but authorization decides what they are allowed to do. In ASP.NET Core MVC, combining ASP.NET Core Identity with Role-Based Authorization provides a powerful, claim-backed mechanism to lock down controllers, action methods, and user interfaces based on assigned roles (such as Admin, Manager, or User).

This comprehensive guide walks through setting up, configuring, and implementing complete Role-Based Authorization from scratch.

Step 1: Enabling Role Management in Program.cs

By default, ASP.NET Core Identity configures user authentication stores. To support roles, you must chain .AddRoles<IdentityRole>() into your service registration so that Entity Framework Core can scaffold and manage the underlying role tables (AspNetRoles, AspNetUserRoles).

Update your Program.cs configuration:

C#

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using MvcAuthenticationDemo.Data;

var builder = WebApplication.CreateBuilder(args);

// Add Database Context
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// Add Identity with Role Support
builder.Services.AddDefaultIdentity<IdentityUser>(options => 
{
    options.SignIn.RequireConfirmedAccount = false;
    options.Password.RequireDigit = true;
    options.Password.RequiredLength = 6;
})
.AddRoles<IdentityRole>() // <-- Enables Role Manager services
.AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.AddControllersWithViews();

var app = builder.Build();

// Pipeline middleware configuration...
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

Step 2: Bootstrapping Roles and an Admin User via Seeding

To prevent your application from launching with zero roles or administrative accounts, you can seed default roles (Admin, User) and create a default super-admin user directly when the application starts up.

Add this database seeding block right before app.Run(); in Program.cs:

C#

// --- Role and Admin Seeding Block ---
using (var scope = app.Services.CreateScope())
{
    var services = scope.ServiceProvider;
    try
    {
        var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
        var userManager = services.GetRequiredService<UserManager<IdentityUser>>();

        // 1. Create Default Roles
        string[] roleNames = { "Admin", "Manager", "User" };
        foreach (var roleName in roleNames)
        {
            if (!await roleManager.RoleExistsAsync(roleName))
            {
                await roleManager.CreateAsync(new IdentityRole(roleName));
            }
        }

        // 2. Create Default Admin User
        string adminEmail = "[email protected]";
        var adminUser = await userManager.FindByEmailAsync(adminEmail);
        if (adminUser == null)
        {
            adminUser = new IdentityUser 
            { 
                UserName = adminEmail, 
                Email = adminEmail, 
                EmailConfirmed = true 
            };
            
            // Create user with a secure temporary password
            var createAdmin = await userManager.CreateAsync(adminUser, "Admin@12345");
            if (createAdmin.Succeeded)
            {
                await userManager.AddToRoleAsync(adminUser, "Admin");
            }
        }
    }
    catch (Exception ex)
    {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred while seeding the database with roles.");
    }
}
// ------------------------------------

app.Run();

Step 3: Protecting Controllers and Action Methods

Once roles are established, securing your endpoints is straightforward using the built-in [Authorize] attribute paired with the Roles parameter. ASP.NET Core will automatically evaluate the authenticated user's claims and reject unauthorized requests with a 403 Forbidden response.

Securing an Entire Controller

If an entire dashboard or management suite should only be accessible by administrators, apply the attribute at the class level:

C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
    public IActionResult Index()
    {
        return View(); // Only accessible by users in the 'Admin' role
    }
}

Securing Specific Action Methods (Multiple Roles)

You can target individual actions and allow multiple comma-separated roles access to specific methods:

C#

[Authorize(Roles = "Admin, Manager")]
[HttpPost]
public IActionResult DeleteRecord(int id)
{
    // Accessible by users in either 'Admin' or 'Manager' roles
    return RedirectToAction("Index");
}

Step 4: Conditionally Rendering UI Elements in Razor Views

Authorization isn't just about blocking backend controller routes; it's also about keeping unauthorized options hidden from the user interface to improve user experience.

You can check whether a user belongs to a role directly inside your Razor layouts or views using User.IsInRole():

HTML

<ul class="navbar-nav ms-auto">
    <li class="nav-item">
        <a class="nav-link text-dark" asp-controller="Home" asp-action="Index">Home</a>
    </li>

    @if (User.Identity != null && User.Identity.IsAuthenticated)
    {
        <!-- Show for any logged-in user -->
        <li class="nav-item">
            <span class="nav-link text-muted">Hello, @User.Identity.Name</span>
        </li>

        @if (User.IsInRole("Admin"))
        {
            <!-- Show exclusively for Administrators -->
            <li class="nav-item">
                <a class="nav-link text-danger fw-bold" asp-controller="Admin" asp-action="Index">Admin Panel</a>
            </li>
        }

        <li class="nav-item">
            <form asp-controller="Account" asp-action="Logout" method="post">
                <button type="submit" class="nav-link btn btn-link text-dark">Logout</button>
            </form>
        </li>
    }
    else
    {
        <li class="nav-item">
            <a class="nav-link text-dark" asp-controller="Account" asp-action="Login">Login</a>
        </li>
    }
</ul>

Conclusion

By integrating ASP.NET Core Identity roles with Program.cs configurations, [Authorize(Roles = "...")] attributes, and conditional Razor views, you establish a resilient, secure foundation for multi-tiered application architecture.