using System.Security.Claims; using Jiaowu.Api.Domain.Identity; namespace Jiaowu.Api.Infrastructure.Auth; public interface ICurrentUserDataScope { CurrentUserScope Current { get; } } public sealed record CurrentUserScope( Guid UserId, string? DisplayName, Guid? CollegeId, DataScope Scope, IReadOnlySet Roles) { public bool IsInRole(string role) => Roles.Contains(role); public bool CanAccessCollege(Guid collegeId) => Scope == DataScope.All || Scope == DataScope.College && CollegeId == collegeId; public Guid? RestrictedCollegeId => Scope switch { DataScope.All => null, DataScope.College => CollegeId ?? Guid.Empty, _ => Guid.Empty }; } public sealed class CurrentUserDataScope(IHttpContextAccessor httpContextAccessor) : ICurrentUserDataScope { public CurrentUserScope Current { get { var principal = httpContextAccessor.HttpContext?.User; var roles = new HashSet( principal?.FindAll(ClaimTypes.Role).Select(x => x.Value) ?? [], StringComparer.OrdinalIgnoreCase); return new CurrentUserScope( ParseGuid(principal?.FindFirstValue(ClaimTypes.NameIdentifier)), principal?.FindFirstValue("display_name") ?? principal?.FindFirstValue(ClaimTypes.Name), ParseNullableGuid(principal?.FindFirstValue("college_id")), EffectiveDataScopeResolver.Resolve(roles), roles); } } private static Guid ParseGuid(string? value) => Guid.TryParse(value, out var id) ? id : Guid.Empty; private static Guid? ParseNullableGuid(string? value) => Guid.TryParse(value, out var id) ? id : null; } public static class EffectiveDataScopeResolver { private static readonly IReadOnlyDictionary RoleScopes = new Dictionary(StringComparer.OrdinalIgnoreCase) { [SystemRoles.SuperAdmin] = DataScope.All, [SystemRoles.AcademicAdmin] = DataScope.All, [SystemRoles.Leader] = DataScope.All, [SystemRoles.CollegeAdmin] = DataScope.College, [SystemRoles.Counselor] = DataScope.Class, [SystemRoles.Teacher] = DataScope.Self, [SystemRoles.Student] = DataScope.Self }; public static DataScope Resolve(IEnumerable roles) { var effectiveScope = DataScope.Self; foreach (var role in roles) { if (RoleScopes.TryGetValue(role, out var roleScope) && roleScope > effectiveScope) { effectiveScope = roleScope; } } return effectiveScope; } }