using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Features;
using Abp.Authorization;
using Abp.Collections.Extensions;
using Abp.Domain.Services;
using Abp.Domain.Uow;
using Abp.Localization;
using Abp.MultiTenancy;
using Abp.Runtime.Caching;
using IwbZero.Authorization.Base.Permissions;
using IwbZero.Authorization.Base.Roles;
using IwbZero.Authorization.Users;
using IwbZero.IdentityFramework;
using IwbZero.Runtime.Caching;
using IwbZero.Runtime.Session;
using IwbZero.Zero.Configuration;
using Microsoft.AspNet.Identity;
namespace IwbZero.Authorization.Roles
{
///
/// Extends of ASP.NET Identity Framework.
/// Applications should derive this class with appropriate generic arguments.
///
public abstract class IwbRoleManager
: RoleManager,
IDomainService
where TRole : IwbSysRole, new()
where TUser : IwbSysUser
{
public ILocalizationManager LocalizationManager { get; set; }
protected string LocalizationSourceName { get; set; }
public IIwbSession AbpSession { get; set; }
public IRoleManagementConfig RoleManagementConfig { get; private set; }
public FeatureDependencyContext FeatureDependencyContext { get; set; }
private IRolePermissionStore RolePermissionStore
{
get
{
if (!(Store is IRolePermissionStore))
{
throw new AbpException("Store is not IRolePermissionStore");
}
return Store as IRolePermissionStore;
}
}
protected IwbRoleStore IwbStore { get; private set; }
protected IPermissionManager PermissionManager { get; }
protected ICacheManager CacheManager { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
//private readonly IRepository _organizationUnitRepository;
//private readonly IRepository _organizationUnitRoleRepository;
///
/// Constructor.
///
protected IwbRoleManager(
IwbRoleStore store,
IPermissionManager permissionManager,
IRoleManagementConfig roleManagementConfig,
ICacheManager cacheManager,
IUnitOfWorkManager unitOfWorkManager)
: base(store)
{
PermissionManager = permissionManager;
CacheManager = cacheManager;
UnitOfWorkManager = unitOfWorkManager;
RoleManagementConfig = roleManagementConfig;
IwbStore = store;
AbpSession = NullIwbSession.Instance;
LocalizationManager = NullLocalizationManager.Instance;
LocalizationSourceName = IwbZeroConsts.LocalizationSourceName;
}
///
/// Checks if a role is granted for a permission.
///
/// The role's name to check it's permission
/// Name of the permission
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(string roleName, string permissionName)
{
return await IsGrantedAsync((await GetRoleByNameAsync(roleName)).Id, PermissionManager.GetPermission(permissionName));
}
///
/// Checks if a role has a permission.
///
/// The role's id to check it's permission
/// Name of the permission
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(int roleId, string permissionName)
{
return await IsGrantedAsync(roleId, PermissionManager.GetPermission(permissionName));
}
///
/// Checks if a role is granted for a permission.
///
/// The role
/// The permission
/// True, if the role has the permission
public Task IsGrantedAsync(TRole role, Permission permission)
{
return IsGrantedAsync(role.Id, permission);
}
///
/// Checks if a role is granted for a permission.
///
/// role id
/// The permission
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(int roleId, Permission permission)
{
//Get cached role permissions
var cacheItem = await GetRolePermissionCacheItemAsync(roleId);
//Check the permission
return cacheItem.GrantedPermissions.Contains(permission.Name);
}
///
/// Checks if a role is granted for a permission.
///
/// role
///
/// The permission
///
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(TRole role, string dataKey, int operType, Permission permission)
{
return await IsGrantedAsync(role.Id, dataKey, operType, permission.Name);
}
///
/// Checks if a role is granted for a permission.
///
/// role id
///
/// The permission
///
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(int roleId, string dataKey, int operType, Permission permission)
{
return await IsGrantedAsync(roleId, dataKey, operType, permission.Name);
}
///
/// Checks if a role is granted for a permission.
///
/// role
///
/// The permission
///
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(TRole role, string dataKey, int operType, string permissionName)
{
return await IsGrantedAsync(role.Id, dataKey, operType, permissionName);
}
///
/// Checks if a role is granted for a data Permission.
///
/// role id
///
/// The permission
///
/// True, if the role has the permission
public virtual async Task IsGrantedAsync(int roleId, string dataKey, int operType, string permissionName)
{
//Get cached role permissions
var cacheItem = await GetRoleDataPermissionCacheItemAsync(roleId);
//Check the permission
// ReSharper disable once PossibleUnintendedLinearSearchInSet
return cacheItem.GrantedPermissions.Contains($"{permissionName}@{dataKey}@{operType}", DataPermissionNameComparer.Instance);
}
///
/// Gets granted permission names for a role.
///
/// Role id
/// List of granted permissions
public virtual async Task> GetGrantedPermissionsAsync(int roleId)
{
return await GetGrantedPermissionsAsync(await GetRoleByIdAsync(roleId));
}
///
/// Gets granted permission names for a role.
///
/// Role name
/// List of granted permissions
public virtual async Task> GetGrantedPermissionsAsync(string roleName)
{
return await GetGrantedPermissionsAsync(await GetRoleByNameAsync(roleName));
}
///
/// Gets granted permissions for a role.
///
/// Role
/// List of granted permissions
public virtual async Task> GetGrantedPermissionsAsync(TRole role)
{
var permissionList = new List();
foreach (var permission in PermissionManager.GetAllPermissions())
{
if (await IsGrantedAsync(role.Id, permission))
{
permissionList.Add(permission);
}
}
return permissionList;
}
///
/// Sets all granted permissions of a role at once.
/// Prohibits all other permissions.
///
/// Role id
/// Permissions
public virtual async Task SetGrantedPermissionsAsync(int roleId, IEnumerable permissions)
{
await SetGrantedPermissionsAsync(await GetRoleByIdAsync(roleId), permissions);
}
///
/// Sets all granted permissions of a role at once.
/// Prohibits all other permissions.
///
/// The role
/// Permissions
public virtual async Task SetGrantedPermissionsAsync(TRole role, IEnumerable permissions)
{
var oldPermissions = await GetGrantedPermissionsAsync(role);
var newPermissions = permissions.ToArray();
foreach (var permission in oldPermissions.Where(p => !newPermissions.Contains(p, PermissionEqualityComparer.Instance)))
{
//await ProhibitPermissionAsync(role, permission);
await RemovePermissionAsync(role, permission);
}
foreach (var permission in newPermissions.Where(p => !oldPermissions.Contains(p, PermissionEqualityComparer.Instance)))
{
await GrantPermissionAsync(role, permission);
}
}
///
/// Grants a permission for a role.
///
/// Role
/// Permission
public async Task GrantPermissionAsync(TRole 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));
await SetGrantedPermissionCacheItem(role.Id, permission.Name);
}
///
/// Prohibits a permission for a role.
///
/// Role
/// Permission
public async Task ProhibitPermissionAsync(TRole 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));
await SetGrantedPermissionCacheItem(role.Id, permission.Name, false);
}
///
/// Prohibits a permission for a role.
///
/// Role
/// Permission
public async Task RemovePermissionAsync(TRole role, Permission permission)
{
if (!await IsGrantedAsync(role.Id, permission))
{
return;
}
await RolePermissionStore.RemovePermissionAsync(role, new PermissionGrantInfo(permission.Name, true));
await SetGrantedPermissionCacheItem(role.Id, permission.Name, false);
}
///
/// Prohibits all permissions for a role.
///
/// Role
public async Task ProhibitAllPermissionsAsync(TRole role)
{
foreach (var permission in PermissionManager.GetAllPermissions())
{
await ProhibitPermissionAsync(role, permission);
}
}
private async Task SetGrantedPermissionCacheItem(int roleId, string permissionName, bool isAdded = true)
{
var permissionCacheItem = await GetRolePermissionCacheItemAsync(roleId);
if (isAdded)
permissionCacheItem.GrantedPermissions.AddIfNotContains(permissionName);
else
permissionCacheItem.GrantedPermissions.Remove(permissionName);
}
///
/// Resets all permission settings for a role.
/// It removes all permission settings for the role.
///
/// Role
public async Task ResetAllPermissionsAsync(TRole role)
{
await RolePermissionStore.RemoveAllPermissionSettingsAsync(role);
}
///
/// Creates a role.
///
/// Role
public override async Task CreateAsync(TRole role)
{
role.SetNormalizedName();
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(TRole role)
{
role.SetNormalizedName();
var result = await CheckDuplicateRoleNameAsync(role.Id, role.Name, role.DisplayName);
if (!result.Succeeded)
{
return result;
}
return await base.UpdateAsync(role);
}
///
/// Deletes a role.
///
/// Role
public override async Task DeleteAsync(TRole role)
{
if (role.IsStatic)
{
return AbpIdentityResult.Failed(string.Format(L("CanNotDeleteStaticRole"), role.Name));
}
return await base.DeleteAsync(role);
}
///
/// Gets a role by given id.
/// Throws exception if no role with given id.
///
/// Role id
/// Role
/// Throws exception if no role with given id
public virtual async Task GetRoleByIdAsync(int roleId)
{
var role = await FindByIdAsync(roleId);
if (role == null)
{
throw new AbpException("There is no role with id: " + roleId);
}
return role;
}
///
/// Gets a role by given name.
/// Throws exception if no role with given roleName.
///
/// Role name
/// Role
/// Throws exception if no role with given roleName
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;
}
public async Task GrantAllPermissionsAsync(TRole role)
{
FeatureDependencyContext.TenantId = role.TenantId;
var permissions = PermissionManager.GetAllPermissions(role.GetMultiTenancySide())
.Where(permission =>
permission.FeatureDependency == null ||
permission.FeatureDependency.IsSatisfied(FeatureDependencyContext)
);
await SetGrantedPermissionsAsync(role, permissions);
}
[UnitOfWork]
public virtual async Task CreateStaticRoles(int tenantId)
{
var staticRoleDefinitions = RoleManagementConfig.StaticRoles.Where(sr => sr.Side == MultiTenancySides.Tenant);
using (UnitOfWorkManager.Current.SetTenantId(tenantId))
{
foreach (var staticRoleDefinition in staticRoleDefinitions)
{
var role = new TRole
{
TenantId = tenantId,
Name = staticRoleDefinition.RoleName,
DisplayName = staticRoleDefinition.RoleName,
AccountType = 1,
RoleType = 0,
IsStatic = true
};
role.SetNormalizedName();
var identityResult = await CreateAsync(role);
if (!identityResult.Succeeded)
{
return identityResult;
}
}
}
return IdentityResult.Success;
}
[UnitOfWork]
public virtual async Task CreateStaticRoles(int tenantId, TRole role)
{
var staticRoleDefinitions = RoleManagementConfig.StaticRoles.Where(sr => sr.Side == MultiTenancySides.Tenant);
using (UnitOfWorkManager.Current.SetTenantId(tenantId))
{
foreach (var staticRoleDefinition in staticRoleDefinitions)
{
role.TenantId = tenantId;
role.Name = staticRoleDefinition.RoleName;
role.DisplayName = staticRoleDefinition.RoleName;
role.IsStatic = true;
role.SetNormalizedName();
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)
{
return AbpIdentityResult.Failed(string.Format(L("RoleNameIsAlreadyTaken"), name));
}
role = await FindByDisplayNameAsync(displayName);
if (role != null && role.Id != expectedRoleId)
{
return AbpIdentityResult.Failed(string.Format(L("RoleDisplayNameIsAlreadyTaken"), displayName));
}
return IdentityResult.Success;
}
private Task FindByDisplayNameAsync(string displayName)
{
return IwbStore.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);
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 == role.GetMultiTenancySide());
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 async Task GetRoleDataPermissionCacheItemAsync(int roleId)
{
var cacheKey = $"Data-{roleId}@{GetCurrentTenantId() ?? 0}";
return await CacheManager.GetRolePermissionCache().GetAsync(cacheKey, async () =>
{
var newCacheItem = new RolePermissionCacheItem(roleId);
var role = await Store.FindByIdAsync(roleId);
if (role == null)
{
throw new AbpException("There is no role with given id: " + roleId);
}
foreach (var permissionInfo in await RolePermissionStore.GetPermissionsAsync(roleId))
{
if (permissionInfo.IsGranted)
{
if (permissionInfo.OperType == 1)
{
newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Create}");
newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Update}");
newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Delete}");
newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{(int)OperType.Query}");
}
else
{
newCacheItem.GrantedPermissions.AddIfNotContains($"{permissionInfo.Name}@{permissionInfo.DataKey}@{permissionInfo.OperType}");
}
}
else
{
newCacheItem.GrantedPermissions.Remove($"{permissionInfo.Name}@{permissionInfo.DataKey}@{permissionInfo.OperType}");
}
}
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);
}
private int? GetCurrentTenantId()
{
if (UnitOfWorkManager.Current != null)
{
return UnitOfWorkManager.Current.GetTenantId();
}
return AbpSession.TenantId;
}
}
}