Three Elements of Authorization
Subject, resource, and operation. For example: a user (subject) reading and writing (operations) a file (resource). The relationship among subject, resource, and operation is called an authorization relation. Based on this relationship, we can abstract it into a triple (subject, resource, operation), and this triple is the basic unit of authorization.
Role-Based Access Control
Role-Based Access Control (RBAC) is an access control model that manages users’ access to resources through roles. A role is a collection of permissions, and users acquire the corresponding permissions by being assigned roles. The role-based access control model is simple and easy to use. There are other access control models as well, such as Attribute-Based Access Control (ABAC).
Permission Access Control List
An Access Control List (ACL) is a permission control model used to manage users’ access to resources. An ACL controls users’ operation permissions on a resource by defining an access control list for each resource.
ACL Storage Design
public class PermissionGranted
{
public int Id { get; set; }
public int RoleId { get; set; }
public required string PermissionName { get; set; }
public string? ResourceType { get; set; }
public string? ResourceId { get; set; }
}
Configuring the ACL Entity in the DbContext
public void Configure(EntityTypeBuilder<PermissionGranted> builder)
{
builder.ToTable("PermissionGranted");
builder.Property(x => x.Id);
builder.Property(x => x.PermissionName).HasMaxLength(64);
builder.Property(x => x.ResourceType).HasMaxLength(16);
builder.Property(x => x.ResourceId).HasMaxLength(32);
builder.HasOne<Role>().WithMany().HasForeignKey(x => x.RoleId).IsRequired();
builder.HasIndex(x => new { x.RoleId, x.PermissionName, x.ResourceType, x.ResourceId }).IsUnique();
}
Permission ACL Storage Design
public class PermissionGranted
{
public int Id { get; set; }
public int RoleId { get; set; }
public required string PermissionName { get; set; }
public string? ResourceType { get; set; }
public string? ResourceId { get; set; }
}
Configuring the ACL Entity in the DbContext
public void Configure(EntityTypeBuilder<PermissionGranted> builder)
{
builder.ToTable("PermissionGranted");
builder.Property(x => x.Id);
builder.Property(x => x.PermissionName).HasMaxLength(64);
builder.Property(x => x.ResourceType).HasMaxLength(16);
builder.Property(x => x.ResourceId).HasMaxLength(32);
builder.HasOne<Role>().WithMany().HasForeignKey(x => x.RoleId).IsRequired();
builder.HasIndex(x => new { x.RoleId, x.PermissionName, x.ResourceType, x.ResourceId }).IsUnique();
}
Designing a Permission Checker
public interface IPermissionChecker
{
Task<bool> IsGrantedAsync(string name, string? resourceType = null, string? resourceId = null);
Task<bool> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name, string? resourceType = null, string? resourceId = null);
}
Implementing the Abstract Permission Checker
Iterate over the permissions of each role; if any role has the permission, return true to indicate that authorization is granted.
public abstract class PermissionChecker : IPermissionChecker
{
public abstract Task<bool> IsGrantedAsync(string name, string? resourceType = null, string? resourceId = null);
public abstract Task<bool> IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string name, string? resourceType = null, string? resourceId = null);
}
Implementing Permission Checkers
The ACL list is stored in the database. You can implement a local permission checker via the DbContext, or a remote permission checker via HttpClient.
public class RemotePermissionChecker: PermissionChecker
public class LocalPermissionChecker: PermissionChecker