Permission System
Moka.Auth provides a flexible and granular permission system that allows you to control access to your application’s resources.
Overview
The permission system is built on these core concepts:
- Permissions: Individual access rights (e.g., “users.read”, “users.write”)
- Roles: Groups of permissions (e.g., “Admin”, “User”)
- Users: Can have both direct permissions and role-based permissions
Setting Up Permissions
1. Using YAML Configuration
Create a seed-data.yaml file:
permissions: - name: users.read description: Can read user data - name: users.write description: Can modify user data - name: roles.manage description: Can manage roles - name: permissions.manage description: Can manage permissions
roles: - name: Admin description: Administrator role permissions: - users.read - users.write - roles.manage - permissions.manage - name: User description: Basic user role permissions: - users.read
users: - username: admin password: Admin123! roles: - Admin permissions: - permissions.manageLoad the configuration:
var yamlFilePath = Path.Combine(app.Environment.ContentRootPath, "seed-data.yaml");await app.SeedMokaAuthDataFromYamlAsync(yamlFilePath);2. Using JSON Configuration
Create a seed-data.json file:
{ "permissions": [ { "name": "users.read", "description": "Can read user data" }, { "name": "users.write", "description": "Can modify user data" } ], "roles": [ { "name": "Admin", "description": "Administrator role", "permissions": ["users.read", "users.write"] } ], "users": [ { "username": "admin", "password": "Admin123!", "roles": ["Admin"], "permissions": ["permissions.manage"] } ]}Load the configuration:
var jsonFilePath = Path.Combine(app.Environment.ContentRootPath, "seed-data.json");await app.SeedMokaAuthDataFromJsonAsync(jsonFilePath);3. Using Environment Variables
Set environment variables:
MOKA_AUTH_PERMISSIONS='users.read,users.write,roles.manage'MOKA_AUTH_ADMIN_ROLE_PERMISSIONS='users.read,users.write'MOKA_AUTH_USER_ROLE_PERMISSIONS='users.read'Load from environment:
await app.SeedMokaAuthDataFromEnvironmentAsync();4. Programmatic Configuration
await app.SeedMokaAuthDataAsync(new MokaAuthSeederOptions{ Permissions = [ new PermissionSeedConfiguration { Name = "users.read", Description = "Can read user data" }, new PermissionSeedConfiguration { Name = "users.write", Description = "Can modify user data" } ], Roles = [ new RoleSeedConfiguration { Name = "Admin", Description = "Administrator role", Permissions = ["users.read", "users.write"] }, new RoleSeedConfiguration { Name = "User", Description = "Basic user role", Permissions = ["users.read"] } ], UseTransaction = true, // Use transaction for safety ThrowOnError = false, // Don't throw on error, just log it RecreateDefaults = false // Don't update existing entities});Using Permissions
1. Attribute-based Authorization
Use the RequirePermission attribute to protect endpoints:
[RequirePermission("users.read")][HttpGet]public IActionResult GetUsers(){ return Ok(_userService.GetUsers());}
// Require multiple permissions[RequirePermission("users.read", "users.write")][HttpPost]public IActionResult CreateUser([FromBody] CreateUserRequest request){ return Ok(_userService.CreateUser(request));}2. Programmatic Authorization
Check permissions in your code:
public class UserService{ private readonly IPermissionService _permissionService;
public async Task<bool> CanUserAccessResource(string userId, string resource) { return await _permissionService.UserHasPermissionAsync(userId, $"{resource}.read"); }}Managing Permissions
1. Creating Permissions
public class PermissionController : ControllerBase{ private readonly IPermissionService _permissionService;
[RequirePermission("permissions.create")] [HttpPost] public async Task<IActionResult> CreatePermission([FromBody] CreatePermissionRequest request) { var permission = await _permissionService.CreatePermissionAsync( request.Name, request.Description ); return Ok(permission); }}2. Assigning Permissions
// Assign to Userawait _permissionService.AssignPermissionToUserAsync(userId, permissionId);
// Assign to Roleawait _permissionService.AssignPermissionToRoleAsync(roleId, permissionId);Permission Inheritance
Moka.Auth supports permission inheritance through roles:
// Create a role hierarchyawait _roleService.CreateRoleAsync("User", "Basic user role");await _roleService.CreateRoleAsync("Editor", "Can edit content");await _roleService.CreateRoleAsync("Admin", "Full system access");
// Set up inheritanceawait _roleService.AddRoleToRoleAsync("Admin", "Editor");await _roleService.AddRoleToRoleAsync("Editor", "User");Common Permission Patterns
CRUD Operations
// Define permissionsawait _permissionService.CreatePermissionAsync("users.create");await _permissionService.CreatePermissionAsync("users.read");await _permissionService.CreatePermissionAsync("users.update");await _permissionService.CreatePermissionAsync("users.delete");
// Create role with CRUD permissionsvar permissions = new[] { "users.create", "users.read", "users.update", "users.delete" };await _roleService.CreateRoleWithPermissionsAsync("UserManager", permissions);Resource-based Permissions
// Fine-grained resource permissionsawait _permissionService.CreatePermissionAsync("documents.read.public");await _permissionService.CreatePermissionAsync("documents.read.private");await _permissionService.CreatePermissionAsync("documents.read.confidential");Checking Multiple Permissions
Using OR Logic
[RequirePermission("documents.read.public", "documents.read.private", RequirementOperator.Or)]public IActionResult GetDocument(string id){ // User can access if they have either permission return Ok(_documentService.GetDocument(id));}Using AND Logic
[RequirePermission("documents.read", "documents.share")]public IActionResult ShareDocument(string id){ // User must have both permissions return Ok(_documentService.ShareDocument(id));}