
October 1, 2026 13:43 by
Peter
Real-world applications frequently need more precise control, even while Role-Based Authorization manages broad access levels like Admin or User. What happens if access is contingent on a number of factors, such as the user's age, location, or ownership of the particular resource they are attempting to modify? ASP.NET Core offers Policy-Based Authorization for these complex situations. A policy, statements, assertions, assertions, constructed.
This is a building that covers everything 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:
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:
// --- 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:
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:
[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.