由于访问人数过多,我今天从新整理一下ABP权限认证机制,帮助大家更容易读懂
1、Abp 的权限拦截主要通过过滤器, public class AbpAuthorizationFilter : IAsyncAuthorizationFilter, ITransientDependency 实现的,他的代码如下
public class AbpAuthorizationFilter : IAsyncAuthorizationFilter, ITransientDependency { public ILogger Logger { get; set; } private readonly IAuthorizationHelper _authorizationHelper; private readonly IErrorInfoBuilder _errorInfoBuilder; private readonly IEventBus _eventBus; public AbpAuthorizationFilter( IAuthorizationHelper authorizationHelper, IErrorInfoBuilder errorInfoBuilder, IEventBus eventBus) { _authorizationHelper = authorizationHelper; _errorInfoBuilder = errorInfoBuilder; _eventBus = eventBus; Logger = NullLogger.Instance; } public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { // Allow Anonymous skips all authorization if (context.Filters.Any(item => item is IAllowAnonymousFilter)) { return; } if (!context.ActionDescriptor.IsControllerAction()) { return; } //TODO: Avoid using try/catch, use conditional checking try { await _authorizationHelper.AuthorizeAsync( context.ActionDescriptor.GetMethodInfo(), context.ActionDescriptor.GetMethodInfo().DeclaringType ); } catch (AbpAuthorizationException ex) { Logger.Warn(ex.ToString(), ex); _eventBus.Trigger(this, new AbpHandledExceptionData(ex)); if (ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType)) { context.Result = new ObjectResult(new AjaxResponse(_errorInfoBuilder.BuildForException(ex), true)) { StatusCode = context.HttpContext.User.Identity.IsAuthenticated ? (int) System.Net.HttpStatusCode.Forbidden : (int) System.Net.HttpStatusCode.Unauthorized }; } else { context.Result = new ChallengeResult(); } } catch (Exception ex) { Logger.Error(ex.ToString(), ex); _eventBus.Trigger(this, new AbpHandledExceptionData(ex)); if (ActionResultHelper.IsObjectResult(context.ActionDescriptor.GetMethodInfo().ReturnType)) { context.Result = new ObjectResult(new AjaxResponse(_errorInfoBuilder.BuildForException(ex))) { StatusCode = (int) System.Net.HttpStatusCode.InternalServerError }; } else { //TODO: How to return Error page? context.Result = new StatusCodeResult((int)System.Net.HttpStatusCode.InternalServerError); } } } }
他的核心代码:
await _authorizationHelper.AuthorizeAsync( context.ActionDescriptor.GetMethodInfo(), context.ActionDescriptor.GetMethodInfo().DeclaringType );
要拦截异常处理,前提是类或者方法上面有AbpAuthorization 特性,我们来看看AbpAuthorization
/// <summary> /// This attribute is used on a method of an Application Service (A class that implements <see cref="IApplicationService"/>) /// to make that method usable only by authorized users. /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class AbpAuthorizeAttribute : Attribute, IAbpAuthorizeAttribute { /// <summary> /// A list of permissions to authorize. /// </summary> public string[] Permissions { get; } /// <summary> /// If this property is set to true, all of the <see cref="Permissions"/> must be granted. /// If it's false, at least one of the <see cref="Permissions"/> must be granted. /// Default: false. /// </summary> public bool RequireAllPermissions { get; set; } /// <summary> /// Creates a new instance of <see cref="AbpAuthorizeAttribute"/> class. /// </summary> /// <param name="permissions">A list of permissions to authorize</param> public AbpAuthorizeAttribute(params string[] permissions) { Permissions = permissions; } }
权限检查帮助类:AuthorizationHelper
public class AuthorizationHelper : IAuthorizationHelper, ITransientDependency { public IAbpSession AbpSession { get; set; } public IPermissionChecker PermissionChecker { get; set; } public IFeatureChecker FeatureChecker { get; set; } public ILocalizationManager LocalizationManager { get; set; } private readonly IFeatureChecker _featureChecker; private readonly IAuthorizationConfiguration _authConfiguration; public AuthorizationHelper(IFeatureChecker featureChecker, IAuthorizationConfiguration authConfiguration) { _featureChecker = featureChecker; _authConfiguration = authConfiguration; AbpSession = NullAbpSession.Instance; PermissionChecker = NullPermissionChecker.Instance; LocalizationManager = NullLocalizationManager.Instance; } //验证权限 public virtual async Task AuthorizeAsync(IEnumerable<IAbpAuthorizeAttribute> authorizeAttributes) { if (!_authConfiguration.IsEnabled) { return; } //判断当前用户是否登录 if (!AbpSession.UserId.HasValue) { //交给异常程序处理 throw new AbpAuthorizationException( LocalizationManager.GetString(AbpConsts.LocalizationSourceName, "CurrentUserDidNotLoginToTheApplication") ); } //检查所有权限 foreach (var authorizeAttribute in authorizeAttributes) { await PermissionChecker.AuthorizeAsync(authorizeAttribute.RequireAllPermissions, authorizeAttribute.Permissions); } } public virtual async Task AuthorizeAsync(MethodInfo methodInfo, Type type) { await CheckFeatures(methodInfo, type); await CheckPermissions(methodInfo, type); } protected virtual async Task CheckFeatures(MethodInfo methodInfo, Type type) { //检查必要特性 var featureAttributes = ReflectionHelper.GetAttributesOfMemberAndType<RequiresFeatureAttribute>(methodInfo, type); if (featureAttributes.Count <= 0) { return; } foreach (var featureAttribute in featureAttributes) { await _featureChecker.CheckEnabledAsync(featureAttribute.RequiresAll, featureAttribute.Features); } } protected virtual async Task CheckPermissions(MethodInfo methodInfo, Type type) { //判断是否开启验证 if (!_authConfiguration.IsEnabled) { return; } //是否有AllowAnonymous标记 if (AllowAnonymous(methodInfo, type)) { return; } //判断方法上面是否有AbpAuthorizeAttribute属性,没有就跳过 var authorizeAttributes = ReflectionHelper .GetAttributesOfMemberAndType(methodInfo, type) .OfType<IAbpAuthorizeAttribute>() .ToArray(); if (!authorizeAttributes.Any()) { return; } //验证权限 await AuthorizeAsync(authorizeAttributes); } private static bool AllowAnonymous(MemberInfo memberInfo, Type type) { return ReflectionHelper .GetAttributesOfMemberAndType(memberInfo, type) .OfType<IAbpAllowAnonymousAttribute>() .Any(); } }
权限检查主要通过这个类实现的,PermissionCheckerExtensions,他的核心方法 public static async Task AuthorizeAsync(this IPermissionChecker permissionChecker, bool requireAll, params string[] permissionNames)
PermissionCheckerExtensions 类的实现如下:
public static class PermissionCheckerExtensions { /// <summary> /// Checks if current user is granted for a permission. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="permissionName">Name of the permission</param> public static bool IsGranted(this IPermissionChecker permissionChecker, string permissionName) { return AsyncHelper.RunSync(() => permissionChecker.IsGrantedAsync(permissionName)); } /// <summary> /// Checks if a user is granted for a permission. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="user">User to check</param> /// <param name="permissionName">Name of the permission</param> public static bool IsGranted(this IPermissionChecker permissionChecker, UserIdentifier user, string permissionName) { return AsyncHelper.RunSync(() => permissionChecker.IsGrantedAsync(user, permissionName)); } /// <summary> /// Checks if given user is granted for given permission. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="user">User</param> /// <param name="requiresAll">True, to require all given permissions are granted. False, to require one or more.</param> /// <param name="permissionNames">Name of the permissions</param> public static bool IsGranted(this IPermissionChecker permissionChecker, UserIdentifier user, bool requiresAll, params string[] permissionNames) { return AsyncHelper.RunSync(() => IsGrantedAsync(permissionChecker, user, requiresAll, permissionNames)); } /// <summary> /// Checks if given user is granted for given permission. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="user">User</param> /// <param name="requiresAll">True, to require all given permissions are granted. False, to require one or more.</param> /// <param name="permissionNames">Name of the permissions</param> public static async Task<bool> IsGrantedAsync(this IPermissionChecker permissionChecker, UserIdentifier user, bool requiresAll, params string[] permissionNames) { if (permissionNames.IsNullOrEmpty()) { return true; } if (requiresAll) { foreach (var permissionName in permissionNames) { if (!(await permissionChecker.IsGrantedAsync(user, permissionName))) { return false; } } return true; } else { foreach (var permissionName in permissionNames) { if (await permissionChecker.IsGrantedAsync(user, permissionName)) { return true; } } return false; } } /// <summary> /// Checks if current user is granted for given permission. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="requiresAll">True, to require all given permissions are granted. False, to require one or more.</param> /// <param name="permissionNames">Name of the permissions</param> public static bool IsGranted(this IPermissionChecker permissionChecker, bool requiresAll, params string[] permissionNames) { return AsyncHelper.RunSync(() => IsGrantedAsync(permissionChecker, requiresAll, permissionNames)); } /// <summary> /// Checks if current user is granted for given permission. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="requiresAll">True, to require all given permissions are granted. False, to require one or more.</param> /// <param name="permissionNames">Name of the permissions</param> public static async Task<bool> IsGrantedAsync(this IPermissionChecker permissionChecker, bool requiresAll, params string[] permissionNames) { //权限为空 if (permissionNames.IsNullOrEmpty()) { return true; } //检查所有权限 if (requiresAll) { foreach (var permissionName in permissionNames) { //检查权限 if (!(await permissionChecker.IsGrantedAsync(permissionName))) { return false; } } return true; } else { foreach (var permissionName in permissionNames) { if (await permissionChecker.IsGrantedAsync(permissionName)) { return true; } } return false; } } /// <summary> /// Authorizes current user for given permission or permissions, /// throws <see cref="AbpAuthorizationException"/> if not authorized. /// User it authorized if any of the <see cref="permissionNames"/> are granted. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="permissionNames">Name of the permissions to authorize</param> /// <exception cref="AbpAuthorizationException">Throws authorization exception if</exception> public static void Authorize(this IPermissionChecker permissionChecker, params string[] permissionNames) { Authorize(permissionChecker, false, permissionNames); } /// <summary> /// Authorizes current user for given permission or permissions, /// throws <see cref="AbpAuthorizationException"/> if not authorized. /// User it authorized if any of the <see cref="permissionNames"/> are granted. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="requireAll"> /// If this is set to true, all of the <see cref="permissionNames"/> must be granted. /// If it's false, at least one of the <see cref="permissionNames"/> must be granted. /// </param> /// <param name="permissionNames">Name of the permissions to authorize</param> /// <exception cref="AbpAuthorizationException">Throws authorization exception if</exception> public static void Authorize(this IPermissionChecker permissionChecker, bool requireAll, params string[] permissionNames) { AsyncHelper.RunSync(() => AuthorizeAsync(permissionChecker, requireAll, permissionNames)); } /// <summary> /// Authorizes current user for given permission or permissions, /// throws <see cref="AbpAuthorizationException"/> if not authorized. /// User it authorized if any of the <see cref="permissionNames"/> are granted. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="permissionNames">Name of the permissions to authorize</param> /// <exception cref="AbpAuthorizationException">Throws authorization exception if</exception> public static Task AuthorizeAsync(this IPermissionChecker permissionChecker, params string[] permissionNames) { return AuthorizeAsync(permissionChecker, false, permissionNames); } /// <summary> /// Authorizes current user for given permission or permissions, /// throws <see cref="AbpAuthorizationException"/> if not authorized. /// </summary> /// <param name="permissionChecker">Permission checker</param> /// <param name="requireAll"> /// If this is set to true, all of the <see cref="permissionNames"/> must be granted. /// If it's false, at least one of the <see cref="permissionNames"/> must be granted. /// </param> /// <param name="permissionNames">Name of the permissions to authorize</param> /// <exception cref="AbpAuthorizationException">Throws authorization exception if</exception> public static async Task AuthorizeAsync(this IPermissionChecker permissionChecker, bool requireAll, params string[] permissionNames) { if (await IsGrantedAsync(permissionChecker, requireAll, permissionNames)) { return; } var localizedPermissionNames = LocalizePermissionNames(permissionChecker, permissionNames); if (requireAll) { throw new AbpAuthorizationException( string.Format( L( permissionChecker, "AllOfThesePermissionsMustBeGranted", "Required permissions are not granted. All of these permissions must be granted: {0}" ), string.Join(", ", localizedPermissionNames) ) ); } else { throw new AbpAuthorizationException( string.Format( L( permissionChecker, "AtLeastOneOfThesePermissionsMustBeGranted", "Required permissions are not granted. At least one of these permissions must be granted: {0}" ), string.Join(", ", localizedPermissionNames) ) ); } } public static string L(IPermissionChecker permissionChecker, string name, string defaultValue) { if (!(permissionChecker is IIocManagerAccessor)) { return defaultValue; } var iocManager = (permissionChecker as IIocManagerAccessor).IocManager; using (var localizationManager = iocManager.ResolveAsDisposable<ILocalizationManager>()) { return localizationManager.Object.GetString(AbpConsts.LocalizationSourceName, name); } } public static string[] LocalizePermissionNames(IPermissionChecker permissionChecker, string[] permissionNames) { if (!(permissionChecker is IIocManagerAccessor)) { return permissionNames; } var iocManager = (permissionChecker as IIocManagerAccessor).IocManager; using (var localizationContext = iocManager.ResolveAsDisposable<ILocalizationContext>()) { using (var permissionManager = iocManager.ResolveAsDisposable<IPermissionManager>()) { return permissionNames.Select(permissionName => { var permission = permissionManager.Object.GetPermissionOrNull(permissionName); return permission?.DisplayName == null ? permissionName : permission.DisplayName.Localize(localizationContext.Object); }).ToArray(); } } } }
以上大家会发现核心代码是 await _userManager.IsGrantedAsync(userId, permissionName);,这个类是在AbpUserManager,而这个类是用户管理的类,里面涉及的东西很多,比如Identity Server 4,我们只需要理解大概意思
public class AbpUserManager<TRole, TUser> : UserManager<TUser>, IDomainService where TRole : AbpRole<TUser>, new() where TUser : AbpUser<TUser> { protected IUserPermissionStore<TUser> UserPermissionStore { get { if (!(Store is IUserPermissionStore<TUser>)) { throw new AbpException("Store is not IUserPermissionStore"); } return Store as IUserPermissionStore<TUser>; } } public ILocalizationManager LocalizationManager { get; set; } protected string LocalizationSourceName { get; set; } public IAbpSession AbpSession { get; set; } public FeatureDependencyContext FeatureDependencyContext { get; set; } protected AbpRoleManager<TRole, TUser> RoleManager { get; } protected AbpUserStore<TRole, TUser> AbpUserStore { get; } public IMultiTenancyConfig MultiTenancy { get; set; } private readonly IPermissionManager _permissionManager; private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly ICacheManager _cacheManager; private readonly IRepository<OrganizationUnit, long> _organizationUnitRepository; private readonly IRepository<UserOrganizationUnit, long> _userOrganizationUnitRepository; private readonly IOrganizationUnitSettings _organizationUnitSettings; private readonly ISettingManager _settingManager; private readonly IOptions<IdentityOptions> _optionsAccessor; public AbpUserManager( AbpRoleManager<TRole, TUser> roleManager, AbpUserStore<TRole, TUser> userStore, IOptions<IdentityOptions> optionsAccessor, IPasswordHasher<TUser> passwordHasher, IEnumerable<IUserValidator<TUser>> userValidators, IEnumerable<IPasswordValidator<TUser>> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<TUser>> logger, IPermissionManager permissionManager, IUnitOfWorkManager unitOfWorkManager, ICacheManager cacheManager, IRepository<OrganizationUnit, long> organizationUnitRepository, IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository, IOrganizationUnitSettings organizationUnitSettings, ISettingManager settingManager) : base( userStore, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger) { _permissionManager = permissionManager; _unitOfWorkManager = unitOfWorkManager; _cacheManager = cacheManager; _organizationUnitRepository = organizationUnitRepository; _userOrganizationUnitRepository = userOrganizationUnitRepository; _organizationUnitSettings = organizationUnitSettings; _settingManager = settingManager; _optionsAccessor = optionsAccessor; AbpUserStore = userStore; RoleManager = roleManager; LocalizationManager = NullLocalizationManager.Instance; LocalizationSourceName = AbpZeroConsts.LocalizationSourceName; } public override async Task<IdentityResult> CreateAsync(TUser user) { var result = await CheckDuplicateUsernameOrEmailAddressAsync(user.Id, user.UserName, user.EmailAddress); if (!result.Succeeded) { return result; } var tenantId = GetCurrentTenantId(); if (tenantId.HasValue && !user.TenantId.HasValue) { user.TenantId = tenantId.Value; } var isLockoutEnabled = user.IsLockoutEnabled; var identityResult = await base.CreateAsync(user); if (identityResult.Succeeded) { await SetLockoutEnabledAsync(user, isLockoutEnabled); } return identityResult; } /// <summary> /// Check whether a user is granted for a permission. /// </summary> /// <param name="userId">User id</param> /// <param name="permissionName">Permission name</param> public virtual async Task<bool> IsGrantedAsync(long userId, string permissionName) { return await IsGrantedAsync( userId, _permissionManager.GetPermission(permissionName) ); } /// <summary> /// Check whether a user is granted for a permission. /// </summary> /// <param name="user">User</param> /// <param name="permission">Permission</param> public virtual Task<bool> IsGrantedAsync(TUser user, Permission permission) { return IsGrantedAsync(user.Id, permission); } /// <summary> /// Check whether a user is granted for a permission. /// </summary> /// <param name="userId">User id</param> /// <param name="permission">Permission</param> public virtual async Task<bool> IsGrantedAsync(long userId, Permission permission) { //Check for multi-tenancy side,检查权限是否标记了多租户 if (!permission.MultiTenancySides.HasFlag(GetCurrentMultiTenancySide())) { return false; } //Check for depended features if (permission.FeatureDependency != null && GetCurrentMultiTenancySide() == MultiTenancySides.Tenant) { FeatureDependencyContext.TenantId = GetCurrentTenantId(); if (!await permission.FeatureDependency.IsSatisfiedAsync(FeatureDependencyContext)) { return false; } } //Get cached user permissions var cacheItem = await GetUserPermissionCacheItemAsync(userId); if (cacheItem == null) { return false; } //Check for user-specific value if (cacheItem.GrantedPermissions.Contains(permission.Name)) { return true; } if (cacheItem.ProhibitedPermissions.Contains(permission.Name)) { return false; } //Check for roles foreach (var roleId in cacheItem.RoleIds) { if (await RoleManager.IsGrantedAsync(roleId, permission)) { return true; } } return false; } /// <summary> /// Gets granted permissions for a user. /// </summary> /// <param name="user">Role</param> /// <returns>List of granted permissions</returns> public virtual async Task<IReadOnlyList<Permission>> GetGrantedPermissionsAsync(TUser user) { var permissionList = new List<Permission>(); foreach (var permission in _permissionManager.GetAllPermissions()) { if (await IsGrantedAsync(user.Id, permission)) { permissionList.Add(permission); } } return permissionList; } /// <summary> /// Sets all granted permissions of a user at once. /// Prohibits all other permissions. /// </summary> /// <param name="user">The user</param> /// <param name="permissions">Permissions</param> public virtual async Task SetGrantedPermissionsAsync(TUser user, IEnumerable<Permission> permissions) { var oldPermissions = await GetGrantedPermissionsAsync(user); var newPermissions = permissions.ToArray(); foreach (var permission in oldPermissions.Where(p => !newPermissions.Contains(p))) { await ProhibitPermissionAsync(user, permission); } foreach (var permission in newPermissions.Where(p => !oldPermissions.Contains(p))) { await GrantPermissionAsync(user, permission); } } /// <summary> /// Prohibits all permissions for a user. /// </summary> /// <param name="user">User</param> public async Task ProhibitAllPermissionsAsync(TUser user) { foreach (var permission in _permissionManager.GetAllPermissions()) { await ProhibitPermissionAsync(user, permission); } } /// <summary> /// Resets all permission settings for a user. /// It removes all permission settings for the user. /// User will have permissions according to his roles. /// This method does not prohibit all permissions. /// For that, use <see cref="ProhibitAllPermissionsAsync"/>. /// </summary> /// <param name="user">User</param> public async Task ResetAllPermissionsAsync(TUser user) { await UserPermissionStore.RemoveAllPermissionSettingsAsync(user); } /// <summary> /// Grants a permission for a user if not already granted. /// </summary> /// <param name="user">User</param> /// <param name="permission">Permission</param> public virtual async Task GrantPermissionAsync(TUser user, Permission permission) { await UserPermissionStore.RemovePermissionAsync(user, new PermissionGrantInfo(permission.Name, false)); if (await IsGrantedAsync(user.Id, permission)) { return; } await UserPermissionStore.AddPermissionAsync(user, new PermissionGrantInfo(permission.Name, true)); } /// <summary> /// Prohibits a permission for a user if it's granted. /// </summary> /// <param name="user">User</param> /// <param name="permission">Permission</param> public virtual async Task ProhibitPermissionAsync(TUser user, Permission permission) { await UserPermissionStore.RemovePermissionAsync(user, new PermissionGrantInfo(permission.Name, true)); if (!await IsGrantedAsync(user.Id, permission)) { return; } await UserPermissionStore.AddPermissionAsync(user, new PermissionGrantInfo(permission.Name, false)); } public virtual Task<TUser> FindByNameOrEmailAsync(string userNameOrEmailAddress) { return AbpUserStore.FindByNameOrEmailAsync(userNameOrEmailAddress); } public virtual Task<List<TUser>> FindAllAsync(UserLoginInfo login) { return AbpUserStore.FindAllAsync(login); } public virtual Task<TUser> FindAsync(int? tenantId, UserLoginInfo login) { return AbpUserStore.FindAsync(tenantId, login); } public virtual Task<TUser> FindByNameOrEmailAsync(int? tenantId, string userNameOrEmailAddress) { return AbpUserStore.FindByNameOrEmailAsync(tenantId, userNameOrEmailAddress); } /// <summary> /// Gets a user by given id. /// Throws exception if no user found with given id. /// </summary> /// <param name="userId">User id</param> /// <returns>User</returns> /// <exception cref="AbpException">Throws exception if no user found with given id</exception> public virtual async Task<TUser> GetUserByIdAsync(long userId) { var user = await FindByIdAsync(userId.ToString()); if (user == null) { throw new AbpException("There is no user with id: " + userId); } return user; } public override async Task<IdentityResult> UpdateAsync(TUser user) { var result = await CheckDuplicateUsernameOrEmailAddressAsync(user.Id, user.UserName, user.EmailAddress); if (!result.Succeeded) { return result; } //Admin user's username can not be changed! if (user.UserName != AbpUserBase.AdminUserName) { if ((await GetOldUserNameAsync(user.Id)) == AbpUserBase.AdminUserName) { throw new UserFriendlyException(string.Format(L("CanNotRenameAdminUser"), AbpUserBase.AdminUserName)); } } return await base.UpdateAsync(user); } public override async Task<IdentityResult> DeleteAsync(TUser user) { if (user.UserName == AbpUserBase.AdminUserName) { throw new UserFriendlyException(string.Format(L("CanNotDeleteAdminUser"), AbpUserBase.AdminUserName)); } return await base.DeleteAsync(user); } public virtual async Task<IdentityResult> ChangePasswordAsync(TUser user, string newPassword) { var errors = new List<IdentityError>(); foreach (var validator in PasswordValidators) { var validationResult = await validator.ValidateAsync(this, user, newPassword); if (!validationResult.Succeeded) { errors.AddRange(validationResult.Errors); } } if (errors.Any()) { return IdentityResult.Failed(errors.ToArray()); } await AbpUserStore.SetPasswordHashAsync(user, PasswordHasher.HashPassword(user, newPassword)); return IdentityResult.Success; } public virtual async Task<IdentityResult> CheckDuplicateUsernameOrEmailAddressAsync(long? expectedUserId, string userName, string emailAddress) { var user = (await FindByNameAsync(userName)); if (user != null && user.Id != expectedUserId) { throw new UserFriendlyException(string.Format(L("Identity.DuplicateUserName"), userName)); } user = (await FindByEmailAsync(emailAddress)); if (user != null && user.Id != expectedUserId) { throw new UserFriendlyException(string.Format(L("Identity.DuplicateEmail"), emailAddress)); } return IdentityResult.Success; } public virtual async Task<IdentityResult> SetRoles(TUser user, string[] roleNames) { await AbpUserStore.UserRepository.EnsureCollectionLoadedAsync(user, u => u.Roles); //Remove from removed roles foreach (var userRole in user.Roles.ToList()) { var role = await RoleManager.FindByIdAsync(userRole.RoleId.ToString()); if (roleNames.All(roleName => role.Name != roleName)) { var result = await RemoveFromRoleAsync(user, role.Name); if (!result.Succeeded) { return result; } } } //Add to added roles foreach (var roleName in roleNames) { var role = await RoleManager.GetRoleByNameAsync(roleName); if (user.Roles.All(ur => ur.RoleId != role.Id)) { var result = await AddToRoleAsync(user, roleName); if (!result.Succeeded) { return result; } } } return IdentityResult.Success; } public virtual async Task<bool> IsInOrganizationUnitAsync(long userId, long ouId) { return await IsInOrganizationUnitAsync( await GetUserByIdAsync(userId), await _organizationUnitRepository.GetAsync(ouId) ); } public virtual async Task<bool> IsInOrganizationUnitAsync(TUser user, OrganizationUnit ou) { return await _userOrganizationUnitRepository.CountAsync(uou => uou.UserId == user.Id && uou.OrganizationUnitId == ou.Id ) > 0; } public virtual async Task AddToOrganizationUnitAsync(long userId, long ouId) { await AddToOrganizationUnitAsync( await GetUserByIdAsync(userId), await _organizationUnitRepository.GetAsync(ouId) ); } public virtual async Task AddToOrganizationUnitAsync(TUser user, OrganizationUnit ou) { var currentOus = await GetOrganizationUnitsAsync(user); if (currentOus.Any(cou => cou.Id == ou.Id)) { return; } await CheckMaxUserOrganizationUnitMembershipCountAsync(user.TenantId, currentOus.Count + 1); await _userOrganizationUnitRepository.InsertAsync(new UserOrganizationUnit(user.TenantId, user.Id, ou.Id)); } public virtual async Task RemoveFromOrganizationUnitAsync(long userId, long ouId) { await RemoveFromOrganizationUnitAsync( await GetUserByIdAsync(userId), await _organizationUnitRepository.GetAsync(ouId) ); } public virtual async Task RemoveFromOrganizationUnitAsync(TUser user, OrganizationUnit ou) { await _userOrganizationUnitRepository.DeleteAsync(uou => uou.UserId == user.Id && uou.OrganizationUnitId == ou.Id); } public virtual async Task SetOrganizationUnitsAsync(long userId, params long[] organizationUnitIds) { await SetOrganizationUnitsAsync( await GetUserByIdAsync(userId), organizationUnitIds ); } private async Task CheckMaxUserOrganizationUnitMembershipCountAsync(int? tenantId, int requestedCount) { var maxCount = await _organizationUnitSettings.GetMaxUserMembershipCountAsync(tenantId); if (requestedCount > maxCount) { throw new AbpException($"Can not set more than {maxCount} organization unit for a user!"); } } public virtual async Task SetOrganizationUnitsAsync(TUser user, params long[] organizationUnitIds) { if (organizationUnitIds == null) { organizationUnitIds = new long[0]; } await CheckMaxUserOrganizationUnitMembershipCountAsync(user.TenantId, organizationUnitIds.Length); var currentOus = await GetOrganizationUnitsAsync(user); //Remove from removed OUs foreach (var currentOu in currentOus) { if (!organizationUnitIds.Contains(currentOu.Id)) { await RemoveFromOrganizationUnitAsync(user, currentOu); } } //Add to added OUs foreach (var organizationUnitId in organizationUnitIds) { if (currentOus.All(ou => ou.Id != organizationUnitId)) { await AddToOrganizationUnitAsync( user, await _organizationUnitRepository.GetAsync(organizationUnitId) ); } } } [UnitOfWork] public virtual Task<List<OrganizationUnit>> GetOrganizationUnitsAsync(TUser user) { var query = from uou in _userOrganizationUnitRepository.GetAll() join ou in _organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id where uou.UserId == user.Id select ou; return Task.FromResult(query.ToList()); } [UnitOfWork] public virtual Task<List<TUser>> GetUsersInOrganizationUnit(OrganizationUnit organizationUnit, bool includeChildren = false) { if (!includeChildren) { var query = from uou in _userOrganizationUnitRepository.GetAll() join user in Users on uou.UserId equals user.Id where uou.OrganizationUnitId == organizationUnit.Id select user; return Task.FromResult(query.ToList()); } else { var query = from uou in _userOrganizationUnitRepository.GetAll() join user in Users on uou.UserId equals user.Id join ou in _organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id where ou.Code.StartsWith(organizationUnit.Code) select user; return Task.FromResult(query.ToList()); } } public virtual async Task InitializeOptionsAsync(int? tenantId) { Options = JsonConvert.DeserializeObject<IdentityOptions>(_optionsAccessor.Value.ToJsonString()); //Lockout Options.Lockout.AllowedForNewUsers = await IsTrueAsync(AbpZeroSettingNames.UserManagement.UserLockOut.IsEnabled, tenantId); Options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(await GetSettingValueAsync<int>(AbpZeroSettingNames.UserManagement.UserLockOut.DefaultAccountLockoutSeconds, tenantId)); Options.Lockout.MaxFailedAccessAttempts = await GetSettingValueAsync<int>(AbpZeroSettingNames.UserManagement.UserLockOut.MaxFailedAccessAttemptsBeforeLockout, tenantId); //Password complexity Options.Password.RequireDigit = await GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.PasswordComplexity.RequireDigit, tenantId); Options.Password.RequireLowercase = await GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.PasswordComplexity.RequireLowercase, tenantId); Options.Password.RequireNonAlphanumeric = await GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.PasswordComplexity.RequireNonAlphanumeric, tenantId); Options.Password.RequireUppercase = await GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.PasswordComplexity.RequireUppercase, tenantId); Options.Password.RequiredLength = await GetSettingValueAsync<int>(AbpZeroSettingNames.UserManagement.PasswordComplexity.RequiredLength, tenantId); } protected virtual Task<string> GetOldUserNameAsync(long userId) { return AbpUserStore.GetUserNameFromDatabaseAsync(userId); } private async Task<UserPermissionCacheItem> GetUserPermissionCacheItemAsync(long userId) { var cacheKey = userId + "@" + (GetCurrentTenantId() ?? 0); return await _cacheManager.GetUserPermissionCache().GetAsync(cacheKey, async () => { var user = await FindByIdAsync(userId.ToString()); if (user == null) { return null; } var newCacheItem = new UserPermissionCacheItem(userId); foreach (var roleName in await GetRolesAsync(user)) { newCacheItem.RoleIds.Add((await RoleManager.GetRoleByNameAsync(roleName)).Id); } foreach (var permissionInfo in await UserPermissionStore.GetPermissionsAsync(userId)) { if (permissionInfo.IsGranted) { newCacheItem.GrantedPermissions.Add(permissionInfo.Name); } else { newCacheItem.ProhibitedPermissions.Add(permissionInfo.Name); } } return newCacheItem; }); } public override async Task<IList<string>> GetValidTwoFactorProvidersAsync(TUser user) { var providers = new List<string>(); foreach (var provider in await base.GetValidTwoFactorProvidersAsync(user)) { if (provider == "Email" && !await IsTrueAsync(AbpZeroSettingNames.UserManagement.TwoFactorLogin.IsEmailProviderEnabled, user.TenantId)) { continue; } if (provider == "Phone" && !await IsTrueAsync(AbpZeroSettingNames.UserManagement.TwoFactorLogin.IsSmsProviderEnabled, user.TenantId)) { continue; } providers.Add(provider); } return providers; } private bool IsTrue(string settingName, int? tenantId) { return GetSettingValue<bool>(settingName, tenantId); } private Task<bool> IsTrueAsync(string settingName, int? tenantId) { return GetSettingValueAsync<bool>(settingName, tenantId); } private T GetSettingValue<T>(string settingName, int? tenantId) where T : struct { return tenantId == null ? _settingManager.GetSettingValueForApplication<T>(settingName) : _settingManager.GetSettingValueForTenant<T>(settingName, tenantId.Value); } private Task<T> GetSettingValueAsync<T>(string settingName, int? tenantId) where T : struct { return tenantId == null ? _settingManager.GetSettingValueForApplicationAsync<T>(settingName) : _settingManager.GetSettingValueForTenantAsync<T>(settingName, tenantId.Value); } 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; } private MultiTenancySides GetCurrentMultiTenancySide() { if (_unitOfWorkManager.Current != null) { return MultiTenancy.IsEnabled && !_unitOfWorkManager.Current.GetTenantId().HasValue ? MultiTenancySides.Host : MultiTenancySides.Tenant; } return AbpSession.MultiTenancySide; } public virtual async Task AddTokenValidityKeyAsync( TUser user, string tokenValidityKey, DateTime expireDate, CancellationToken cancellationToken = default(CancellationToken)) { await AbpUserStore.AddTokenValidityKeyAsync(user, tokenValidityKey, expireDate, cancellationToken); } public virtual async Task<bool> IsTokenValidityKeyValidAsync( TUser user, string tokenValidityKey, CancellationToken cancellationToken = default(CancellationToken)) { return await AbpUserStore.IsTokenValidityKeyValidAsync(user, tokenValidityKey, cancellationToken); } public virtual async Task RemoveTokenValidityKeyAsync( TUser user, string tokenValidityKey, CancellationToken cancellationToken = default(CancellationToken)) { await AbpUserStore.RemoveTokenValidityKeyAsync(user, tokenValidityKey, cancellationToken); } }