#nullable enable using Abp; using Abp.Application.Features; using Abp.Authorization; using Abp.Collections.Extensions; using Abp.Domain.Repositories; using Abp.Domain.Services; using Abp.Domain.Uow; using Abp.Localization; using Abp.Runtime.Caching; using Abp.UI; using Microsoft.AspNetCore.Identity; using System.Globalization; using VberZero.BaseSystem.Organizations; using VberZero.BaseSystem.Roles; using VberZero.Caching; using VberZero.Configuration; using VberZero.Session; namespace VberZero.Authorization.Roles; public class VzRoleManager : RoleManager, IDomainService { public ILocalizationManager LocalizationManager { get; set; } protected string LocalizationSourceName { get; set; } public IVzSession AbpSession { get; set; } public IRoleManagementConfig RoleManagementConfig { get; } public FeatureDependencyContext FeatureDependencyContext { get; set; } private IRolePermissionStore RolePermissionStore { get { if (!(Store is IRolePermissionStore)) { throw new AbpException("Store is not IRolePermissionStore"); } return Store as IRolePermissionStore ?? throw new InvalidOperationException(); } } protected VzRoleStore AbpStore { get; } private readonly IPermissionManager _permissionManager; private readonly ICacheManager _cacheManager; private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IRepository _organizationUnitRepository; private readonly IRepository _organizationUniRoleRepository; public VzRoleManager( VzRoleStore store, IEnumerable> roleValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, ILogger logger, IPermissionManager permissionManager, ICacheManager cacheManager, IUnitOfWorkManager unitOfWorkManager, IRoleManagementConfig roleManagementConfig, IRepository organizationUnitRepository, IRepository organizationUniRoleRepository) : base( store, roleValidators, keyNormalizer, errors, logger) { _permissionManager = permissionManager; _cacheManager = cacheManager; _unitOfWorkManager = unitOfWorkManager; RoleManagementConfig = roleManagementConfig; _organizationUnitRepository = organizationUnitRepository; _organizationUniRoleRepository = organizationUniRoleRepository; AbpStore = store; AbpSession = NullVzSession.Instance; LocalizationManager = NullLocalizationManager.Instance; LocalizationSourceName = VzConsts.LocalizationSourceName; } #region Permission #region IsGranted /// /// 检查角色是否被授予权限 /// /// /// /// public virtual async Task IsGrantedAsync(string roleName, string permissionName) { return await IsGrantedAsync((await GetRoleByNameAsync(roleName)).Id, _permissionManager.GetPermission(permissionName)); } /// /// 检查角色是否被授予权限 /// /// /// /// public virtual async Task IsGrantedAsync(int roleId, string permissionName) { return await IsGrantedAsync(roleId, _permissionManager.GetPermission(permissionName)); } /// /// 检查角色是否被授予权限 /// /// /// /// public Task IsGrantedAsync(Role role, Permission permission) { return IsGrantedAsync(role.Id, permission); } /// /// 检查角色是否被授予权限 /// /// /// /// public virtual async Task IsGrantedAsync(int roleId, Permission permission) { //获取缓存的角色权限 var cacheItem = await GetRolePermissionCacheItemAsync(roleId); //检查权限 return cacheItem.GrantedPermissions.Contains(permission.Name); } /// /// 检查角色是否被授予权限 /// /// /// /// public virtual bool IsGranted(int roleId, Permission permission) { //获取缓存的角色权限 var cacheItem = GetRolePermissionCacheItem(roleId); //检查权限 return cacheItem.GrantedPermissions.Contains(permission.Name); } #endregion IsGranted /// /// 获取角色的权限 /// /// /// public virtual async Task> GetGrantedPermissionsAsync(int roleId) { return await GetGrantedPermissionsAsync(await GetRoleByIdAsync(roleId)); } /// /// 获取角色的权限 /// /// /// public virtual async Task> GetGrantedPermissionsAsync(string roleName) { return await GetGrantedPermissionsAsync(await GetRoleByNameAsync(roleName)); } /// /// 获取角色的权限 /// /// /// public virtual async Task> GetGrantedPermissionsAsync(Role role) { var cacheItem = await GetRolePermissionCacheItemAsync(role.Id); var allPermissions = _permissionManager.GetAllPermissions(); return allPermissions.Where(x => cacheItem.GrantedPermissions.Contains(x.Name)).ToList(); } /// /// 一次设置角色的所有授予权限。 /// 禁止所有其他权限 /// /// /// /// true 移除所有其他权限 false禁止所有其他权限 public virtual async Task SetGrantedPermissionsAsync(int roleId, IEnumerable permissions, bool isRemove = true) { await SetGrantedPermissionsAsync(await GetRoleByIdAsync(roleId), permissions); } /// /// 一次设置角色的所有授予权限。 /// 禁止所有其他权限。 /// /// /// /// true 移除所有其他权限 false禁止所有其他权限 public virtual async Task SetGrantedPermissionsAsync(Role role, IEnumerable permissions, bool isRemove = true) { var oldPermissions = await GetGrantedPermissionsAsync(role); var newPermissions = permissions.ToArray(); foreach (var permission in oldPermissions.Where(p => !newPermissions.Contains(p, PermissionEqualityComparer.Instance))) { if (isRemove) { await RemovePermissionAsync(role, permission); } else { await ProhibitPermissionAsync(role, permission); } } foreach (var permission in newPermissions.Where(p => !oldPermissions.Contains(p, PermissionEqualityComparer.Instance))) { await GrantPermissionAsync(role, permission); } } /// /// 授予角色权限 /// /// /// public async Task GrantPermissionAsync(Role role, Permission permission) { if (await IsGrantedAsync(role.Id, permission)) { return; } await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, false)); await RolePermissionStore.AddPermissionAsync(role, new PermissionGrantInfo(permission.Name, true)); } /// /// 移除角色权限 /// /// /// public async Task RemovePermissionAsync(Role role, Permission permission) { if (!await IsGrantedAsync(role.Id, permission)) { return; } await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, true)); } /// /// 禁止角色权限 /// /// /// public async Task ProhibitPermissionAsync(Role role, Permission permission) { if (!await IsGrantedAsync(role.Id, permission)) { return; } await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, true)); await RolePermissionStore.AddPermissionAsync(role, new PermissionGrantInfo(permission.Name, false)); } /// /// 禁止角色的所有权限 /// /// Role public async Task ProhibitAllPermissionsAsync(Role role) { foreach (var permission in _permissionManager.GetAllPermissions()) { await ProhibitPermissionAsync(role, permission); } } /// /// 重置角色的所有权限设置。删除角色的所有权限设置。 /// 角色将拥有 返回 true 的权限 /// /// public async Task ResetAllPermissionsAsync(Role role) { await RolePermissionStore.RemoveAllPermissionSettingsAsync(role); } #endregion Permission /// /// 创建角色 /// /// public override async Task CreateAsync(Role role) { var result = await CheckDuplicateRoleNameAsync(role.Id, role.Name, role.DisplayName); if (!result.Succeeded) { return result; } var tenantId = GetCurrentTenantId(); if (tenantId.HasValue && !role.TenantId.HasValue) { role.TenantId = tenantId.Value; } return await base.CreateAsync(role); } /// /// 修改角色 /// /// /// public override async Task UpdateAsync(Role role) { var result = await CheckDuplicateRoleNameAsync(role.Id, role.Name, role.DisplayName); if (!result.Succeeded) { return result; } return await base.UpdateAsync(role); } /// /// 删除角色 /// /// Role public override async Task DeleteAsync(Role role) { if (role.IsStatic) { throw new UserFriendlyException(string.Format(L("CanNotDeleteStaticRole"), role.Name)); } return await base.DeleteAsync(role); } /// /// 通过给定的 id 获取角色。 /// 如果没有给定 id 的角色,则抛出异常。 /// /// /// Role public virtual async Task GetRoleByIdAsync(int roleId) { var role = await FindByIdAsync(roleId.ToString()); if (role == null) { throw new AbpException("There is no role with id: " + roleId); } return role; } /// /// 通过给定的 roleName 获取角色。 /// 如果没有给定 roleName 的角色,则抛出异常。 /// /// /// Role public virtual async Task GetRoleByNameAsync(string roleName) { var role = await FindByNameAsync(roleName); if (role == null) { throw new AbpException("There is no role with name: " + roleName); } return role; } /// /// 通过给定的 roleName 获取角色。 /// 如果没有给定 roleName 的角色,则抛出异常。 /// /// /// Role public virtual Role GetRoleByName(string roleName) { var normalizedRoleName = roleName.ToUpperInvariant(); var role = AbpStore.FindByName(normalizedRoleName); if (role == null) { throw new AbpException("There is no role with name: " + roleName); } return role; } public async Task GrantAllPermissionsAsync(Role role) { FeatureDependencyContext.TenantId = role.TenantId; var permissions = _permissionManager.GetAllPermissions(Abp.MultiTenancy.MultiTenancyExtensions.GetMultiTenancySide(role)) .Where(permission => permission.FeatureDependency == null || permission.FeatureDependency.IsSatisfied(FeatureDependencyContext) ); await SetGrantedPermissionsAsync(role, permissions); } public virtual async Task CreateStaticRoles(int tenantId) { return await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { var staticRoleDefinitions = RoleManagementConfig.StaticRoles.Where( sr => sr.Side == Abp.MultiTenancy.MultiTenancySides.Tenant ); using (_unitOfWorkManager.Current.SetTenantId(tenantId)) { foreach (var staticRoleDefinition in staticRoleDefinitions) { var role = MapStaticRoleDefinitionToRole(tenantId, staticRoleDefinition); var identityResult = await CreateAsync(role); if (!identityResult.Succeeded) { return identityResult; } } } return IdentityResult.Success; }); } public virtual async Task CheckDuplicateRoleNameAsync( int? expectedRoleId, string name, string displayName) { var role = await FindByNameAsync(name); if (role != null && role.Id != expectedRoleId) { throw new UserFriendlyException(string.Format(L("RoleNameIsAlreadyTaken"), name)); } role = await FindByDisplayNameAsync(displayName); if (role != null && role.Id != expectedRoleId) { throw new UserFriendlyException(string.Format(L("RoleDisplayNameIsAlreadyTaken"), displayName)); } return IdentityResult.Success; } /// /// 获取组织单元的角色 /// /// /// 包括子组织单位的角色。 默认为 false /// public virtual async Task> GetRolesInOrganizationUnit( OrganizationUnit organizationUnit, bool includeChildren = false) { var result = _unitOfWorkManager.WithUnitOfWork(() => { if (!includeChildren) { var query = from organizationUniRole in _organizationUniRoleRepository.GetAll() join role in Roles on organizationUniRole.RoleId equals role.Id where organizationUniRole.OrganizationUnitId == organizationUnit.Id select role; return query.ToList(); } else { var query = from organizationUniRole in _organizationUniRoleRepository.GetAll() join role in Roles on organizationUniRole.RoleId equals role.Id join ou in _organizationUnitRepository.GetAll() on organizationUniRole.OrganizationUnitId equals ou.Id where ou.Path.StartsWith(organizationUnit.Path) select role; return query.ToList(); } }); return await Task.FromResult(result); } public virtual async Task SetOrganizationUnitsAsync(int roleId, params long[]? organizationUnitIds) { await SetOrganizationUnitsAsync( await GetRoleByIdAsync(roleId), organizationUnitIds ); } public virtual async Task SetOrganizationUnitsAsync(Role role, params long[]? organizationUnitIds) { await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { organizationUnitIds ??= Array.Empty(); var currentOus = await GetOrganizationUnitsAsync(role); //Remove from removed OUs foreach (var currentOu in currentOus) { if (!organizationUnitIds.Contains(currentOu.Id)) { await RemoveFromOrganizationUnitAsync(role, currentOu); } } //Add to added OUs foreach (var organizationUnitId in organizationUnitIds) { if (currentOus.All(ou => ou.Id != organizationUnitId)) { await AddToOrganizationUnitAsync( role, await _organizationUnitRepository.GetAsync(organizationUnitId) ); } } }); } public virtual async Task IsInOrganizationUnitAsync(int roleId, long ouId) { return await _unitOfWorkManager.WithUnitOfWorkAsync(async () => await IsInOrganizationUnitAsync( await GetRoleByIdAsync(roleId), await _organizationUnitRepository.GetAsync(ouId) ) ); } public virtual async Task IsInOrganizationUnitAsync(Role role, OrganizationUnit ou) { return await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { return await _organizationUniRoleRepository.CountAsync(uou => uou.RoleId == role.Id && uou.OrganizationUnitId == ou.Id ) > 0; }); } public virtual async Task AddToOrganizationUnitAsync(int roleId, long ouId, int? tenantId) { await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { await AddToOrganizationUnitAsync( await GetRoleByIdAsync(roleId), await _organizationUnitRepository.GetAsync(ouId) ); }); } public virtual async Task AddToOrganizationUnitAsync(Role role, OrganizationUnit ou) { await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { if (await IsInOrganizationUnitAsync(role, ou)) { return; } await _organizationUniRoleRepository.InsertAsync(new OrganizationUnitRole(role.TenantId, role.Id, ou.Id)); }); } public async Task RemoveFromOrganizationUnitAsync(int roleId, long organizationUnitId) { await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { await RemoveFromOrganizationUnitAsync( await GetRoleByIdAsync(roleId), await _organizationUnitRepository.GetAsync(organizationUnitId) ); }); } public virtual async Task RemoveFromOrganizationUnitAsync(Role role, OrganizationUnit ou) { await _unitOfWorkManager.WithUnitOfWorkAsync(async () => { await _organizationUniRoleRepository.DeleteAsync(uor => uor.RoleId == role.Id && uor.OrganizationUnitId == ou.Id ); }); } public virtual async Task> GetOrganizationUnitsAsync(Role role) { var result = _unitOfWorkManager.WithUnitOfWork(() => { var query = from uor in _organizationUniRoleRepository.GetAll() join ou in _organizationUnitRepository.GetAll() on uor.OrganizationUnitId equals ou.Id where uor.RoleId == role.Id select ou; return query.ToList(); }); return await Task.FromResult(result); } private Task FindByDisplayNameAsync(string displayName) { return AbpStore.FindByDisplayNameAsync(displayName); } private async Task GetRolePermissionCacheItemAsync(int roleId) { var cacheKey = roleId + "@" + (GetCurrentTenantId() ?? 0); return await _cacheManager.GetRolePermissionCache().GetAsync(cacheKey, async () => { var newCacheItem = new RolePermissionCacheItem(roleId); var role = await Store.FindByIdAsync(roleId.ToString(), CancellationToken); if (role == null) { throw new AbpException("There is no role with given id: " + roleId); } var staticRoleDefinition = RoleManagementConfig.StaticRoles.FirstOrDefault(r => r.RoleName == role.Name && r.Side == Abp.MultiTenancy.MultiTenancyExtensions.GetMultiTenancySide(role) ); if (staticRoleDefinition != null) { foreach (var permission in _permissionManager.GetAllPermissions()) { if (staticRoleDefinition.IsGrantedByDefault(permission)) { newCacheItem.GrantedPermissions.Add(permission.Name); } } } foreach (var permissionInfo in await RolePermissionStore.GetPermissionsAsync(roleId)) { if (permissionInfo.IsGranted) { newCacheItem.GrantedPermissions.AddIfNotContains(permissionInfo.Name); } else { newCacheItem.GrantedPermissions.Remove(permissionInfo.Name); } } return newCacheItem; }); } private RolePermissionCacheItem GetRolePermissionCacheItem(int roleId) { var cacheKey = roleId + "@" + (GetCurrentTenantId() ?? 0); return _cacheManager.GetRolePermissionCache().Get(cacheKey, () => { var newCacheItem = new RolePermissionCacheItem(roleId); var role = AbpStore.FindById(roleId.ToString(), CancellationToken); if (role == null) { throw new AbpException("There is no role with given id: " + roleId); } var staticRoleDefinition = RoleManagementConfig.StaticRoles.FirstOrDefault(r => r.RoleName == role.Name && r.Side == Abp.MultiTenancy.MultiTenancyExtensions.GetMultiTenancySide(role) ); if (staticRoleDefinition != null) { foreach (var permission in _permissionManager.GetAllPermissions()) { if (staticRoleDefinition.IsGrantedByDefault(permission)) { newCacheItem.GrantedPermissions.Add(permission.Name); } } } foreach (var permissionInfo in RolePermissionStore.GetPermissions(roleId)) { if (permissionInfo.IsGranted) { newCacheItem.GrantedPermissions.AddIfNotContains(permissionInfo.Name); } else { newCacheItem.GrantedPermissions.Remove(permissionInfo.Name); } } return newCacheItem; }); } protected virtual string L(string name) { return LocalizationManager.GetString(LocalizationSourceName, name); } protected virtual string L(string name, CultureInfo cultureInfo) { return LocalizationManager.GetString(LocalizationSourceName, name, cultureInfo); } protected virtual Role MapStaticRoleDefinitionToRole(int tenantId, StaticRoleDefinition staticRoleDefinition) { return new Role { TenantId = tenantId, Name = staticRoleDefinition.RoleName, DisplayName = staticRoleDefinition.RoleDisplayName, IsStatic = true }; } private int? GetCurrentTenantId() { if (_unitOfWorkManager.Current != null) { return _unitOfWorkManager.Current.GetTenantId(); } return AbpSession.TenantId; } }