using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Transactions; using Abp; using Abp.Dependency; using Abp.Domain.Repositories; using Abp.Domain.Uow; using Abp.Linq; using IwbZero.Authorization.Permissions; using IwbZero.Authorization.Roles; using Microsoft.AspNet.Identity; namespace IwbZero.Authorization.Users { public abstract class IwbUserStore : IUserPasswordStore, IUserEmailStore, IUserLoginStore, IUserRoleStore, IQueryableUserStore, IUserLockoutStore, IIwbUserPermissionStore, IUserPhoneNumberStore, //IUserClaimStore, IUserSecurityStampStore, IUserTwoFactorStore, ITransientDependency where TRole : IwbSysRole, new() where TUser : IwbSysUser, new() { public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; } private readonly IRepository _userRepository; private readonly IRepository _roleRepository; private readonly IRepository _userRoleRepository; private readonly IRepository _userLoginRepository; private readonly IRepository _userPermissionSettingRepository; private readonly IUnitOfWorkManager _unitOfWorkManager; /// /// Constructor. /// public IwbUserStore( IRepository userRepository, IRepository userRoleRepository, IRepository roleRepository, IRepository userLoginRepository, IRepository userPermissionSettingRepository, IUnitOfWorkManager unitOfWorkManager) { _userRepository = userRepository; _userRoleRepository = userRoleRepository; _roleRepository = roleRepository; _userLoginRepository = userLoginRepository; _unitOfWorkManager = unitOfWorkManager; _userPermissionSettingRepository = userPermissionSettingRepository; AsyncQueryableExecuter = NullAsyncQueryableExecuter.Instance; } #region IQueryableUserStore public virtual IQueryable Users => _userRepository.GetAll(); #endregion #region IUserStore public virtual async Task CreateAsync(TUser user) { await _userRepository.InsertAsync(user); } public virtual async Task UpdateAsync(TUser user) { await _userRepository.UpdateAsync(user); } public virtual async Task DeleteAsync(TUser user) { await _userRepository.DeleteAsync(user.Id); } public virtual async Task FindByIdAsync(long userId) { return await _userRepository.FirstOrDefaultAsync(userId); } public virtual async Task FindByNameAsync(string userName) { return await _userRepository.FirstOrDefaultAsync( user => user.UserName == userName ); } public virtual async Task FindByEmailAsync(string email) { return await _userRepository.FirstOrDefaultAsync( user => user.EmailAddress == email ); } /// /// Tries to find a user with user name or email address in current tenant. /// /// User name or email address /// User or null public virtual async Task FindByNameOrEmailAsync(string userNameOrEmailAddress) { return await _userRepository.FirstOrDefaultAsync( user => (user.UserName == userNameOrEmailAddress || user.EmailAddress == userNameOrEmailAddress) ); } /// /// Tries to find a user with user name or email address in given tenant. /// /// Tenant Id /// User name or email address /// User or null [UnitOfWork] public virtual async Task FindByNameOrEmailAsync(int? tenantId, string userNameOrEmailAddress) { using (_unitOfWorkManager.Current.SetTenantId(tenantId)) { return await FindByNameOrEmailAsync(userNameOrEmailAddress); } } #endregion #region IUserPasswordStore public virtual Task SetPasswordHashAsync(TUser user, string passwordHash) { user.Password = passwordHash; return Task.FromResult(0); } public virtual Task GetPasswordHashAsync(TUser user) { return Task.FromResult(user.Password); } public virtual Task HasPasswordAsync(TUser user) { return Task.FromResult(!string.IsNullOrEmpty(user.Password)); } #endregion #region IUserEmailStore public virtual Task SetEmailAsync(TUser user, string email) { user.EmailAddress = email; return Task.FromResult(0); } public virtual Task GetEmailAsync(TUser user) { return Task.FromResult(user.EmailAddress); } public virtual Task GetEmailConfirmedAsync(TUser user) { return Task.FromResult(user.IsEmailConfirmed); } public virtual Task SetEmailConfirmedAsync(TUser user, bool confirmed) { user.IsEmailConfirmed = confirmed; return Task.FromResult(0); } #endregion #region IUserLoginStore public virtual async Task AddLoginAsync(TUser user, UserLoginInfo login) { await _userLoginRepository.InsertAsync( new UserLogin { //TenantId = user.TenantId, LoginProvider = login.LoginProvider, ProviderKey = login.ProviderKey, UserId = user.Id }); } public virtual async Task RemoveLoginAsync(TUser user, UserLoginInfo login) { await _userLoginRepository.DeleteAsync( ul => ul.UserId == user.Id && ul.LoginProvider == login.LoginProvider && ul.ProviderKey == login.ProviderKey ); } public virtual async Task> GetLoginsAsync(TUser user) { return (await _userLoginRepository.GetAllListAsync(ul => ul.UserId == user.Id)) .Select(ul => new UserLoginInfo(ul.LoginProvider, ul.ProviderKey)) .ToList(); } public virtual async Task FindAsync(UserLoginInfo login) { var userLogin = await _userLoginRepository.FirstOrDefaultAsync( ul => ul.LoginProvider == login.LoginProvider && ul.ProviderKey == login.ProviderKey ); if (userLogin == null) { return null; } return await _userRepository.FirstOrDefaultAsync(u => u.Id == userLogin.UserId); } [UnitOfWork] public virtual Task> FindAllAsync(UserLoginInfo login) { var query = from userLogin in _userLoginRepository.GetAll() join user in _userRepository.GetAll() on userLogin.UserId equals user.Id where userLogin.LoginProvider == login.LoginProvider && userLogin.ProviderKey == login.ProviderKey select user; return Task.FromResult(query.ToList()); } public virtual Task FindAsync(int? tenantId, UserLoginInfo login) { using (_unitOfWorkManager.Current.SetTenantId(tenantId)) { var query = from userLogin in _userLoginRepository.GetAll() join user in _userRepository.GetAll() on userLogin.UserId equals user.Id where userLogin.LoginProvider == login.LoginProvider && userLogin.ProviderKey == login.ProviderKey select user; return Task.FromResult(query.FirstOrDefault()); } } #endregion #region IUserRoleStore public virtual async Task AddToRoleAsync(TUser user, string roleName) { var role = await GetRoleByNameAsync(roleName); await _userRoleRepository.InsertAsync(new SysUserRole(user.Id, role.Id)); } public virtual async Task RemoveFromRoleAsync(TUser user, string roleName) { var role = await GetRoleByNameAsync(roleName); var userRole = await _userRoleRepository.FirstOrDefaultAsync(ur => ur.UserId == user.Id && ur.RoleId == role.Id); if (userRole == null) { return; } await _userRoleRepository.DeleteAsync(userRole); } [UnitOfWork] public virtual async Task> GetRolesAsync(TUser user) { var query = from userRole in _userRoleRepository.GetAll() join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id where userRole.UserId == user.Id select role.Name; return await AsyncQueryableExecuter.ToListAsync(query); } public virtual async Task IsInRoleAsync(TUser user, string roleName) { var role = await GetRoleByNameAsync(roleName); return await _userRoleRepository.FirstOrDefaultAsync(ur => ur.UserId == user.Id && ur.RoleId == role.Id) != null; } #endregion #region IUserPermissionStore public virtual async Task AddPermissionAsync(TUser user, IwbPermissionGrantInfo iwbPermissionGrant) { if (await HasPermissionAsync(user.Id, iwbPermissionGrant)) { return; } await _userPermissionSettingRepository.InsertAsync( new SysPermission { PermissionNo = Guid.NewGuid().ToString("N"), Master = 1, MasterValue = user.Id + "", PermissionName = iwbPermissionGrant.Name, IsGranted = iwbPermissionGrant.IsGranted }); } public virtual async Task RemovePermissionAsync(TUser user, IwbPermissionGrantInfo iwbPermissionGrant) { await _userPermissionSettingRepository.DeleteAsync( p => p.Master == 1 && p.MasterValue == user.Id + "" && p.PermissionName == iwbPermissionGrant.Name && p.IsGranted == iwbPermissionGrant.IsGranted ); } public virtual async Task> GetPermissionsAsync(long userId) { return (await _userPermissionSettingRepository.GetAllListAsync(p => p.Master == 1 && p.MasterValue == userId + "")) .Select(p => new IwbPermissionGrantInfo(p.PermissionName, p.IsGranted)) .ToList(); } public virtual async Task HasPermissionAsync(long userId, IwbPermissionGrantInfo iwbPermissionGrant) { return await _userPermissionSettingRepository.FirstOrDefaultAsync( p => p.Master == 1 && p.MasterValue == userId + "" && p.PermissionName == iwbPermissionGrant.Name && p.IsGranted == iwbPermissionGrant.IsGranted ) != null; } public virtual async Task RemoveAllPermissionSettingsAsync(TUser user) { await _userPermissionSettingRepository.DeleteAsync(p => p.Master == 1 && p.MasterValue == user.Id + ""); } #endregion #region IUserLockoutStore public Task GetLockoutEndDateAsync(TUser user) { return Task.FromResult( user.LockoutEndDateUtc.HasValue ? new DateTimeOffset(DateTime.SpecifyKind(user.LockoutEndDateUtc.Value, DateTimeKind.Utc)) : new DateTimeOffset() ); } public Task SetLockoutEndDateAsync(TUser user, DateTimeOffset lockoutEnd) { user.LockoutEndDateUtc = lockoutEnd == DateTimeOffset.MinValue ? new DateTime?() : lockoutEnd.UtcDateTime; return Task.FromResult(0); } public Task IncrementAccessFailedCountAsync(TUser user) { return Task.FromResult(++user.AccessFailedCount); } public Task ResetAccessFailedCountAsync(TUser user) { user.AccessFailedCount = 0; return Task.FromResult(0); } public Task GetAccessFailedCountAsync(TUser user) { return Task.FromResult(user.AccessFailedCount); } public Task GetLockoutEnabledAsync(TUser user) { return Task.FromResult(user.IsLockoutEnabled); } public Task SetLockoutEnabledAsync(TUser user, bool enabled) { user.IsLockoutEnabled = enabled; return Task.FromResult(0); } #endregion #region IUserPhoneNumberStore public Task SetPhoneNumberAsync(TUser user, string phoneNumber) { user.PhoneNumber = phoneNumber; return Task.FromResult(0); } public Task GetPhoneNumberAsync(TUser user) { return Task.FromResult(user.PhoneNumber); } public Task GetPhoneNumberConfirmedAsync(TUser user) { return Task.FromResult(user.IsPhoneNumberConfirmed); } public Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed) { user.IsPhoneNumberConfirmed = confirmed; return Task.FromResult(0); } #endregion #region Helpers private async Task GetRoleByNameAsync(string roleName) { var role = await _roleRepository.FirstOrDefaultAsync(r => r.Name == roleName); if (role == null) { throw new AbpException("Could not find a role with name: " + roleName); } return role; } #endregion #region IUserSecurityStampStore public Task SetSecurityStampAsync(TUser user, string stamp) { user.SecurityStamp = stamp; return Task.FromResult(0); } public Task GetSecurityStampAsync(TUser user) { return Task.FromResult(user.SecurityStamp); } #endregion public Task SetTwoFactorEnabledAsync(TUser user, bool enabled) { user.IsTwoFactorEnabled = enabled; return Task.FromResult(0); } public Task GetTwoFactorEnabledAsync(TUser user) { return Task.FromResult(user.IsTwoFactorEnabled); } public async Task GetUserNameFromDatabaseAsync(long userId) { //note: This workaround will not be needed after fixing https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1828 var outerUow = _unitOfWorkManager.Current; using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions { Scope = TransactionScopeOption.RequiresNew, IsTransactional = false, IsolationLevel = IsolationLevel.ReadUncommitted })) { if (outerUow != null) { _unitOfWorkManager.Current.SetTenantId(outerUow.GetTenantId()); } var user = await _userRepository.GetAsync(userId); await uow.CompleteAsync(); return user.UserName; } } public async Task GetUserFromDatabaseAsync(long userId) { //note: This workaround will not be needed after fixing https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1828 var outerUow = _unitOfWorkManager.Current; using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions { Scope = TransactionScopeOption.RequiresNew, IsTransactional = false, IsolationLevel = IsolationLevel.ReadUncommitted })) { if (outerUow != null) { _unitOfWorkManager.Current.SetTenantId(outerUow.GetTenantId()); } var user = await _userRepository.GetAsync(userId); await uow.CompleteAsync(); return user; } } #region IDisposable public virtual void Dispose() { //No need to dispose since using IOC. } #endregion } }