Permission-based authorization in ASP.NET Core allows you to control access to resources based on fine-grained permissions assigned to users or roles. This approach provides greater flexibility compared to role-based authorization by enabling a more detailed and scalable access control system.
- Granular Access Control: Define specific permissions for various actions and resources.
- Dynamic Policy Management: Add or update permissions dynamically without redeploying the application.
- Extensibility: Easily integrate with custom user or role management systems.
- Secure Middleware Integration: Built on ASP.NET Core's robust authentication and authorization pipeline.
- Define Permissions: Create a centralized list of permissions in your application.
- Assign Permissions: Associate permissions with users or roles in your database.
- Validate Permissions: Use custom authorization handlers to enforce permission checks.
- Protect Resources: Apply policies to controllers, actions, or endpoints based on required permissions.
Create a permissions class to store all permissions in a centralized location:
namespace aspDotNetCore.Data
{
public enum Permission
{
ReadProducts = 1,
AddProducts,
EditProducts,
DeleteProducts
}
}namespace aspDotNetCore.Data
{
public class UserPermission
{
public int UserId { get; set; }
public Permission PermissionId { get; set; }
}
}using aspDotNetCore.Data;
namespace aspDotNetCore.Authorization
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class CheckPermissionAttribute: Attribute
{
public CheckPermissionAttribute(Permission permission)
{
Permission = permission;
}
public Permission Permission { get; }
}
}Add claims to users representing their permissions:
[HttpGet]
[Route("")]
[CheckPermission(Permission.ReadProducts)]
public ActionResult<IEnumerable<Product>> GetProducts()
{
var products = _dbContext.Set<Product>().ToList();
return Ok(products);
}using aspDotNetCore.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Security.Claims;
namespace aspDotNetCore.Authorization
{
public class PermissionBasedAuthorizationFilter : IAuthorizationFilter
{
private readonly ApplicationDbContext dbContext;
public PermissionBasedAuthorizationFilter(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var attributes = (CheckPermissionAttribute)context.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x is CheckPermissionAttribute);
if (attributes != null)
{
var claimIdentity = context.HttpContext.User.Identity as ClaimsIdentity;
if (claimIdentity == null || !claimIdentity.IsAuthenticated)
{
context.Result = new ForbidResult();
}
else
{
var userId = int.Parse(claimIdentity.FindFirst(ClaimTypes.NameIdentifier).Value);
var hasPermisssion = dbContext.Set<UserPermission>().Any(x => x.UserId == userId && x.PermissionId == attributes.Permission);
if (!hasPermisssion)
{
context.Result = new ForbidResult();
}
}
}
}
}
}// Program.cs
builder.Services.AddControllers(opt =>
{
opt.Filters.Add<LogActivityFilter>();
opt.Filters.Add<PermissionBasedAuthorizationFilter>();
});- Use HTTPS: Always secure your application with HTTPS.
- Validate Claims: Ensure claims are added securely and verified properly.
- Use Database Storage: Store permissions and associations in a secure database.
- Follow Least Privilege: Assign only necessary permissions to users or roles.
Contributions are welcome! Feel free to submit a pull request or open an issue.
