UserStore.cs 17 KB

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