IwbUserStore.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Security.Claims;
  5. using System.Threading.Tasks;
  6. using System.Transactions;
  7. using Abp;
  8. using Abp.Dependency;
  9. using Abp.Domain.Repositories;
  10. using Abp.Domain.Uow;
  11. using Abp.Linq;
  12. using IwbZero.Authorization.Base.Permissions;
  13. using IwbZero.Authorization.Base.Users;
  14. using IwbZero.Authorization.Roles;
  15. using Microsoft.AspNet.Identity;
  16. namespace IwbZero.Authorization.Users
  17. {
  18. public abstract class IwbUserStore<TRole, TUser> : IUserPasswordStore<TUser, long>,
  19. IUserEmailStore<TUser, long>,
  20. IUserLoginStore<TUser, long>,
  21. IUserRoleStore<TUser, long>,
  22. IQueryableUserStore<TUser, long>,
  23. IUserLockoutStore<TUser, long>,
  24. IUserPermissionStore<TUser>,
  25. IUserPhoneNumberStore<TUser, long>,
  26. IUserClaimStore<TUser, long>,
  27. IUserSecurityStampStore<TUser, long>,
  28. IUserTwoFactorStore<TUser, long>,
  29. ITransientDependency
  30. where TRole : IwbSysRole<TUser>
  31. where TUser : IwbSysUser<TUser>
  32. {
  33. public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }
  34. private readonly IRepository<TUser, long> _userRepository;
  35. private readonly IRepository<UserLogin, long> _userLoginRepository;
  36. private readonly IRepository<UserRole, long> _userRoleRepository;
  37. private readonly IRepository<UserClaim, long> _userClaimRepository;
  38. private readonly IRepository<TRole> _roleRepository;
  39. private readonly IRepository<PermissionSetting, long> _permissionSettingRepository;
  40. private readonly IUnitOfWorkManager _unitOfWorkManager;
  41. /// <summary>
  42. /// Constructor.
  43. /// </summary>
  44. protected IwbUserStore(
  45. IRepository<TUser, long> userRepository,
  46. IRepository<UserLogin, long> userLoginRepository,
  47. IRepository<UserRole, long> userRoleRepository,
  48. IRepository<TRole> roleRepository,
  49. IRepository<PermissionSetting, long> permissionSettingRepository,
  50. IUnitOfWorkManager unitOfWorkManager,
  51. IRepository<UserClaim, long> userClaimRepository)
  52. {
  53. _userRepository = userRepository;
  54. _userLoginRepository = userLoginRepository;
  55. _userRoleRepository = userRoleRepository;
  56. _roleRepository = roleRepository;
  57. _unitOfWorkManager = unitOfWorkManager;
  58. _userClaimRepository = userClaimRepository;
  59. _permissionSettingRepository = permissionSettingRepository;
  60. AsyncQueryableExecuter = NullAsyncQueryableExecuter.Instance;
  61. }
  62. #region IQueryableUserStore
  63. public virtual IQueryable<TUser> Users => _userRepository.GetAll();
  64. #endregion IQueryableUserStore
  65. #region IUserStore
  66. public virtual async Task CreateAsync(TUser user)
  67. {
  68. await _userRepository.InsertAsync(user);
  69. }
  70. public virtual async Task UpdateAsync(TUser user)
  71. {
  72. await _userRepository.UpdateAsync(user);
  73. }
  74. public virtual async Task DeleteAsync(TUser user)
  75. {
  76. await _userRepository.DeleteAsync(user.Id);
  77. }
  78. public virtual async Task<TUser> FindByIdAsync(long userId)
  79. {
  80. return await _userRepository.FirstOrDefaultAsync(a => a.Id == userId);
  81. }
  82. public virtual async Task<TUser> FindByNameAsync(string userName)
  83. {
  84. var normalizedUsername = NormalizeKey(userName);
  85. return await _userRepository.FirstOrDefaultAsync(
  86. user => user.NormalizedUserName == normalizedUsername
  87. );
  88. }
  89. public virtual async Task<TUser> FindByEmailAsync(string email)
  90. {
  91. var normalizedEmail = NormalizeKey(email);
  92. return await _userRepository.FirstOrDefaultAsync(
  93. user => user.NormalizedEmailAddress == normalizedEmail
  94. );
  95. }
  96. /// <summary>
  97. /// Tries to find a user with user name or email address in current tenant.
  98. /// </summary>
  99. /// <param name="userNameOrEmailOrMobile">User name or email address</param>
  100. /// <returns>User or null</returns>
  101. public virtual async Task<TUser> FindByNameOrEmailOrMobileAsync(string userNameOrEmailOrMobile)
  102. {
  103. var normalizedUserNameOrEmailAddress = NormalizeKey(userNameOrEmailOrMobile);
  104. return await _userRepository.FirstOrDefaultAsync(
  105. user => (user.NormalizedUserName == normalizedUserNameOrEmailAddress || user.NormalizedEmailAddress == normalizedUserNameOrEmailAddress || user.PhoneNumber == userNameOrEmailOrMobile)
  106. );
  107. }
  108. /// <summary>
  109. /// Tries to find a user with user name or email address in given tenant.
  110. /// </summary>
  111. /// <param name="tenantId">Tenant Id</param>
  112. /// <param name="userNameOrEmailOrMobile">User name or email address</param>
  113. /// <returns>User or null</returns>
  114. [UnitOfWork]
  115. public virtual async Task<TUser> FindByNameOrEmailOrMobileAsync(int? tenantId, string userNameOrEmailOrMobile)
  116. {
  117. using (_unitOfWorkManager.Current.SetTenantId(tenantId))
  118. {
  119. return await FindByNameOrEmailOrMobileAsync(userNameOrEmailOrMobile);
  120. }
  121. }
  122. #endregion IUserStore
  123. #region IUserPasswordStore
  124. public virtual Task SetPasswordHashAsync(TUser user, string passwordHash)
  125. {
  126. user.Password = passwordHash;
  127. return Task.FromResult(0);
  128. }
  129. public virtual Task<string> GetPasswordHashAsync(TUser user)
  130. {
  131. return Task.FromResult(user.Password);
  132. }
  133. public virtual Task<bool> HasPasswordAsync(TUser user)
  134. {
  135. return Task.FromResult(!string.IsNullOrEmpty(user.Password));
  136. }
  137. #endregion IUserPasswordStore
  138. #region IUserEmailStore
  139. public virtual Task SetEmailAsync(TUser user, string email)
  140. {
  141. user.EmailAddress = email;
  142. return Task.FromResult(0);
  143. }
  144. public virtual Task<string> GetEmailAsync(TUser user)
  145. {
  146. return Task.FromResult(user.EmailAddress);
  147. }
  148. public virtual Task<bool> GetEmailConfirmedAsync(TUser user)
  149. {
  150. return Task.FromResult(user.IsEmailConfirmed);
  151. }
  152. public virtual Task SetEmailConfirmedAsync(TUser user, bool confirmed)
  153. {
  154. user.IsEmailConfirmed = confirmed;
  155. return Task.FromResult(0);
  156. }
  157. #endregion IUserEmailStore
  158. #region IUserLoginStore
  159. public virtual async Task AddLoginAsync(TUser user, UserLoginInfo login)
  160. {
  161. await _userLoginRepository.InsertAsync(
  162. new UserLogin
  163. {
  164. TenantId = user.TenantId,
  165. LoginProvider = login.LoginProvider,
  166. ProviderKey = login.ProviderKey,
  167. UserId = user.Id
  168. });
  169. }
  170. public virtual async Task RemoveLoginAsync(TUser user, UserLoginInfo login)
  171. {
  172. await _userLoginRepository.DeleteAsync(
  173. ul => ul.UserId == user.Id &&
  174. ul.LoginProvider == login.LoginProvider &&
  175. ul.ProviderKey == login.ProviderKey
  176. );
  177. }
  178. public virtual async Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user)
  179. {
  180. return (await _userLoginRepository.GetAllListAsync(ul => ul.UserId == user.Id))
  181. .Select(ul => new UserLoginInfo(ul.LoginProvider, ul.ProviderKey))
  182. .ToList();
  183. }
  184. public virtual async Task<TUser> FindAsync(UserLoginInfo login)
  185. {
  186. var userLogin = await _userLoginRepository.FirstOrDefaultAsync(
  187. ul => ul.LoginProvider == login.LoginProvider && ul.ProviderKey == login.ProviderKey
  188. );
  189. if (userLogin == null)
  190. {
  191. return null;
  192. }
  193. return await _userRepository.FirstOrDefaultAsync(u => u.Id == userLogin.UserId);
  194. }
  195. [UnitOfWork]
  196. public virtual Task<List<TUser>> FindAllAsync(UserLoginInfo login)
  197. {
  198. var query = from userLogin in _userLoginRepository.GetAll()
  199. join user in _userRepository.GetAll() on userLogin.UserId equals user.Id
  200. where userLogin.LoginProvider == login.LoginProvider && userLogin.ProviderKey == login.ProviderKey
  201. select user;
  202. return Task.FromResult(query.ToList());
  203. }
  204. public virtual Task<TUser> FindAsync(int? tenantId, UserLoginInfo login)
  205. {
  206. using (_unitOfWorkManager.Current.SetTenantId(tenantId))
  207. {
  208. var query = from userLogin in _userLoginRepository.GetAll()
  209. join user in _userRepository.GetAll() on userLogin.UserId equals user.Id
  210. where userLogin.LoginProvider == login.LoginProvider && userLogin.ProviderKey == login.ProviderKey
  211. select user;
  212. return Task.FromResult(query.FirstOrDefault());
  213. }
  214. }
  215. #endregion IUserLoginStore
  216. #region IUserRoleStore
  217. public virtual async Task AddToRoleAsync(TUser user, string roleName)
  218. {
  219. var role = await GetRoleByNameAsync(roleName);
  220. await _userRoleRepository.InsertAsync(new UserRole(user.TenantId, user.Id, role.Id));
  221. }
  222. public virtual async Task RemoveFromRoleAsync(TUser user, string roleName)
  223. {
  224. var role = await GetRoleByNameAsync(roleName);
  225. var userRole = await _userRoleRepository.FirstOrDefaultAsync(ur => ur.UserId == user.Id && ur.RoleId == role.Id);
  226. if (userRole == null)
  227. {
  228. return;
  229. }
  230. await _userRoleRepository.DeleteAsync(userRole);
  231. }
  232. [UnitOfWork]
  233. public virtual async Task<IList<string>> GetRolesAsync(TUser user)
  234. {
  235. var userRoles = await AsyncQueryableExecuter.ToListAsync(from userRole in _userRoleRepository.GetAll()
  236. join role in _roleRepository.GetAll() on userRole.RoleId equals role.Id
  237. where userRole.UserId == user.Id
  238. select role.Name);
  239. return userRoles.ToList();
  240. }
  241. public virtual async Task<bool> IsInRoleAsync(TUser user, string roleName)
  242. {
  243. return (await GetRolesAsync(user)).Any(r => r == roleName);
  244. }
  245. #endregion IUserRoleStore
  246. #region IUserPermissionStore
  247. public virtual async Task AddPermissionAsync(TUser user, PermissionGrantInfo permissionGrant)
  248. {
  249. if (await HasPermissionAsync(user.Id, permissionGrant))
  250. {
  251. return;
  252. }
  253. await _permissionSettingRepository.InsertAsync(
  254. new PermissionSetting
  255. {
  256. TenantId = user.TenantId,
  257. Master = 2,
  258. MasterValue = user.Id + "",
  259. Name = permissionGrant.Name,
  260. IsGranted = permissionGrant.IsGranted
  261. });
  262. }
  263. public virtual async Task RemovePermissionAsync(TUser user, PermissionGrantInfo permissionGrant)
  264. {
  265. await _permissionSettingRepository.DeleteAsync(
  266. a => a.Master == 2 && a.MasterValue == user.Id + "" &&
  267. a.Name == permissionGrant.Name &&
  268. a.IsGranted == permissionGrant.IsGranted
  269. );
  270. }
  271. public virtual async Task<IList<PermissionGrantInfo>> GetPermissionsAsync(long userId)
  272. {
  273. var list = (await _permissionSettingRepository.GetAllListAsync(p => p.Master == 2 && p.MasterValue == userId + ""))
  274. .Select(p => new PermissionGrantInfo(p.Name, p.IsGranted))
  275. .ToList();
  276. return list;
  277. }
  278. public virtual async Task<bool> HasPermissionAsync(long userId, PermissionGrantInfo permissionGrant)
  279. {
  280. return await _permissionSettingRepository.FirstOrDefaultAsync(
  281. p => p.Master == 2 && p.MasterValue == userId + "" &&
  282. p.Name == permissionGrant.Name &&
  283. p.IsGranted == permissionGrant.IsGranted
  284. ) != null;
  285. }
  286. public virtual async Task RemoveAllPermissionSettingsAsync(TUser user)
  287. {
  288. await _permissionSettingRepository.DeleteAsync(s => s.Master == 2 && s.MasterValue == user.Id + "");
  289. }
  290. #endregion IUserPermissionStore
  291. #region IUserLockoutStore
  292. public Task<DateTimeOffset> GetLockoutEndDateAsync(TUser user)
  293. {
  294. return Task.FromResult(
  295. user.LockoutEndDateUtc.HasValue
  296. ? new DateTimeOffset(DateTime.SpecifyKind(user.LockoutEndDateUtc.Value, DateTimeKind.Utc))
  297. : new DateTimeOffset()
  298. );
  299. }
  300. public Task SetLockoutEndDateAsync(TUser user, DateTimeOffset lockoutEnd)
  301. {
  302. user.LockoutEndDateUtc = lockoutEnd == DateTimeOffset.MinValue ? new DateTime?() : lockoutEnd.UtcDateTime;
  303. return Task.FromResult(0);
  304. }
  305. public Task<int> IncrementAccessFailedCountAsync(TUser user)
  306. {
  307. return Task.FromResult(++user.AccessFailedCount);
  308. }
  309. public Task ResetAccessFailedCountAsync(TUser user)
  310. {
  311. user.AccessFailedCount = 0;
  312. return Task.FromResult(0);
  313. }
  314. public Task<int> GetAccessFailedCountAsync(TUser user)
  315. {
  316. return Task.FromResult(user.AccessFailedCount);
  317. }
  318. public Task<bool> GetLockoutEnabledAsync(TUser user)
  319. {
  320. return Task.FromResult(user.IsLockoutEnabled);
  321. }
  322. public Task SetLockoutEnabledAsync(TUser user, bool enabled)
  323. {
  324. user.IsLockoutEnabled = enabled;
  325. return Task.FromResult(0);
  326. }
  327. #endregion IUserLockoutStore
  328. #region IUserPhoneNumberStore
  329. public Task SetPhoneNumberAsync(TUser user, string phoneNumber)
  330. {
  331. user.PhoneNumber = phoneNumber;
  332. return Task.FromResult(0);
  333. }
  334. public Task<string> GetPhoneNumberAsync(TUser user)
  335. {
  336. return Task.FromResult(user.PhoneNumber);
  337. }
  338. public Task<bool> GetPhoneNumberConfirmedAsync(TUser user)
  339. {
  340. return Task.FromResult(user.IsPhoneNumberConfirmed);
  341. }
  342. public Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed)
  343. {
  344. user.IsPhoneNumberConfirmed = confirmed;
  345. return Task.FromResult(0);
  346. }
  347. #endregion IUserPhoneNumberStore
  348. #region IUserClaimStore
  349. public async Task<IList<Claim>> GetClaimsAsync(TUser user)
  350. {
  351. var userClaims = await _userClaimRepository.GetAllListAsync(uc => uc.UserId == user.Id);
  352. return userClaims.Select(uc => new Claim(uc.ClaimType, uc.ClaimValue)).ToList();
  353. }
  354. public Task AddClaimAsync(TUser user, Claim claim)
  355. {
  356. return _userClaimRepository.InsertAsync(new UserClaim(user, claim));
  357. }
  358. public Task RemoveClaimAsync(TUser user, Claim claim)
  359. {
  360. return _userClaimRepository.DeleteAsync(
  361. uc => uc.UserId == user.Id &&
  362. uc.ClaimType == claim.Type &&
  363. uc.ClaimValue == claim.Value
  364. );
  365. }
  366. #endregion IUserClaimStore
  367. #region IDisposable
  368. public virtual void Dispose()
  369. {
  370. //No need to dispose since using IOC.
  371. }
  372. #endregion IDisposable
  373. #region Helpers
  374. protected virtual string NormalizeKey(string key)
  375. {
  376. return key.ToUpperInvariant();
  377. }
  378. private async Task<TRole> GetRoleByNameAsync(string roleName)
  379. {
  380. var normalizedName = NormalizeKey(roleName);
  381. var role = await _roleRepository.FirstOrDefaultAsync(r => r.NormalizedName == normalizedName);
  382. if (role == null)
  383. {
  384. throw new AbpException("Could not find a role with name: " + normalizedName);
  385. }
  386. return role;
  387. }
  388. #endregion Helpers
  389. #region IUserSecurityStampStore
  390. public Task SetSecurityStampAsync(TUser user, string stamp)
  391. {
  392. user.SecurityStamp = stamp;
  393. return Task.FromResult(0);
  394. }
  395. public Task<string> GetSecurityStampAsync(TUser user)
  396. {
  397. return Task.FromResult(user.SecurityStamp);
  398. }
  399. #endregion IUserSecurityStampStore
  400. public Task SetTwoFactorEnabledAsync(TUser user, bool enabled)
  401. {
  402. user.IsTwoFactorEnabled = enabled;
  403. return Task.FromResult(0);
  404. }
  405. public Task<bool> GetTwoFactorEnabledAsync(TUser user)
  406. {
  407. return Task.FromResult(user.IsTwoFactorEnabled);
  408. }
  409. public async Task<string> GetUserNameFromDatabaseAsync(long userId)
  410. {
  411. //note: This workaround will not be needed after fixing https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1828
  412. var outerUow = _unitOfWorkManager.Current;
  413. using (var uow = _unitOfWorkManager.Begin(new UnitOfWorkOptions
  414. {
  415. Scope = TransactionScopeOption.RequiresNew,
  416. IsTransactional = false,
  417. IsolationLevel = IsolationLevel.ReadUncommitted
  418. }))
  419. {
  420. if (outerUow != null)
  421. {
  422. _unitOfWorkManager.Current.SetTenantId(outerUow.GetTenantId());
  423. }
  424. var user = await _userRepository.FirstOrDefaultAsync(a => a.Id == userId);
  425. await uow.CompleteAsync();
  426. return user.UserName;
  427. }
  428. }
  429. }
  430. }