Implemented Role-Based Access Control (RBAC) with 5 tenant-level roles following Clean Architecture principles. Changes: - Created TenantRole enum (TenantOwner, TenantAdmin, TenantMember, TenantGuest, AIAgent) - Created UserTenantRole entity with repository pattern - Updated JWT service to include role claims (tenant_role, role) - Updated RegisterTenant to auto-assign TenantOwner role - Updated Login to query and include user role in JWT - Updated RefreshToken to preserve role claims - Added authorization policies in Program.cs (RequireTenantOwner, RequireTenantAdmin, etc.) - Updated /api/auth/me endpoint to return role information - Created EF Core migration for user_tenant_roles table - Applied database migration successfully Database: - New table: identity.user_tenant_roles - Columns: id, user_id, tenant_id, role, assigned_at, assigned_by_user_id - Indexes: user_id, tenant_id, role, unique(user_id, tenant_id) - Foreign keys: CASCADE on user and tenant deletion Testing: - Created test-rbac.ps1 PowerShell script - All RBAC tests passing - JWT tokens contain role claims - Role persists across login and token refresh Documentation: - DAY5-PHASE2-RBAC-IMPLEMENTATION-SUMMARY.md with complete implementation details 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
76 lines
2.4 KiB
C#
76 lines
2.4 KiB
C#
using ColaFlow.Shared.Kernel.Common;
|
|
using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
|
|
|
|
namespace ColaFlow.Modules.Identity.Domain.Aggregates.Users;
|
|
|
|
/// <summary>
|
|
/// Represents a user's role within a specific tenant
|
|
/// </summary>
|
|
public sealed class UserTenantRole : Entity
|
|
{
|
|
public UserId UserId { get; private set; } = null!;
|
|
public TenantId TenantId { get; private set; } = null!;
|
|
public TenantRole Role { get; private set; }
|
|
|
|
public DateTime AssignedAt { get; private set; }
|
|
public Guid? AssignedByUserId { get; private set; }
|
|
|
|
// Navigation properties (optional, for EF Core)
|
|
public User User { get; private set; } = null!;
|
|
public Tenant Tenant { get; private set; } = null!;
|
|
|
|
// Private constructor for EF Core
|
|
private UserTenantRole() : base()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Factory method to create a user-tenant-role assignment
|
|
/// </summary>
|
|
public static UserTenantRole Create(
|
|
UserId userId,
|
|
TenantId tenantId,
|
|
TenantRole role,
|
|
Guid? assignedByUserId = null)
|
|
{
|
|
return new UserTenantRole
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
UserId = userId,
|
|
TenantId = tenantId,
|
|
Role = role,
|
|
AssignedAt = DateTime.UtcNow,
|
|
AssignedByUserId = assignedByUserId
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the user's role (e.g., promote Member to Admin)
|
|
/// </summary>
|
|
public void UpdateRole(TenantRole newRole, Guid updatedByUserId)
|
|
{
|
|
if (Role == newRole)
|
|
return;
|
|
|
|
Role = newRole;
|
|
AssignedByUserId = updatedByUserId;
|
|
// Note: AssignedAt is NOT updated to preserve original assignment timestamp
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if user has permission (extensible for future fine-grained permissions)
|
|
/// </summary>
|
|
public bool HasPermission(string permission)
|
|
{
|
|
// Future implementation: Check permission against role-permission mapping
|
|
// For now, this is a placeholder for fine-grained permission checks
|
|
return Role switch
|
|
{
|
|
TenantRole.TenantOwner => true, // Owner has all permissions
|
|
TenantRole.AIAgent when permission.StartsWith("read") => true,
|
|
TenantRole.AIAgent when permission.StartsWith("write_preview") => true,
|
|
_ => false // Implement specific permission checks as needed
|
|
};
|
|
}
|
|
}
|