Files
ColaFlow/colaflow-api/src/Modules/Identity/ColaFlow.Modules.Identity.Domain/Aggregates/Users/UserTenantRole.cs
Yaojia Wang aaab26ba6c feat(backend): Implement complete RBAC system (Day 5 Phase 2)
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>
2025-11-03 15:00:39 +01:00

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
};
}
}