.net core Identity之基於現有的實體(資料庫模型) 或 自定義User和Role模型
一個系統組織架構是不可少的,所以 認證(authentication) 和 授權(authorization)是必不可少的,但是 微軟很人性化的為我們提供了Identity這個東西,嗯,是好東西,但是總是稍微有那麼一點不足,就是命名,以及部分欄位可能用不到。沒關係,我們可以自定義。
1.第三方或官方提供的便捷方式?
1.1.預設的IdentityUser,IdentityRole :
生成方式沒有什麼好說的,建立專案時,修改下身份驗證方式即可見到,如上面的表結構。這裡涉及到 Claims identityClaims,如果還不知道是什麼 看這裡 應該是最簡的總結了吧
1.2.ids4(identityServer4)生成的表如下:
不得不說ids4很方便,但是有點多有點亂,不是我們想要的,所以怎麼辦呢?
2.簡要分析。
按照我們以前用FX的時候的一貫邏輯,知道identity使用SignInManager,但是SignInManager使用到一個 UserManager物件,而這個UserManager使用到了 UserStore這個東西,好,這樣的話我們就開啟core.Indetity的原始碼再看看訪問資料那裡是如何定義的(因為我們一開始就說了,要自定義或者使用現有的模型)。
很明顯,思路也很明確,UserStore的實現,還是繼承自 Identity.EntityFramework下的一個UserStore,繼續跟進:
到這裡就很直觀了,Framework下面的這個UserStore實現了一系列的介面,在建構函式中注入了預設的上下問物件DbContext,呵呵,找就找到了根源了,那麼我們就重新實現這個UserStore就可以了,將其中的資料上下文DbContext換成我們自己的就好了,我這麼說沒意見吧?
3.重定義UserStore
定義前我們要注意下,2中,泛型涉及到的 引數型別,我們都需要定義,可以直接使用core Identity中定義的,改下名稱即可,我們自定義的UserStore名稱我依舊定義成UserStore.cs: (有點長。。。)
public class UserStore : IQueryableUserStore<User>, IUserLoginStore<User>, IUserClaimStore<User>, IUserPasswordStore<User>, IUserSecurityStampStore<User>, IUserEmailStore<User>, IUserLockoutStore<User>, IUserPhoneNumberStore<User>, IUserTwoFactorStore<User>, IUserAuthenticationTokenStore<User>, IUserAuthenticatorKeyStore<User>, IUserTwoFactorRecoveryCodeStore<User>, IUserRoleStore<User> /*<User, Guid, UserClain, UserLogin, UserToken, Role, Guid, UserRole>*/ { #region ctor public UserStore(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; _userRepository = _unitOfWork.Repository<User, Guid>(); _roleRepository = _unitOfWork.Repository<Role, Guid>(); _userRoleRepository = _unitOfWork.Repository<UserRole, Guid>(); _userLoginRepository = _unitOfWork.Repository<UserLogin, Guid>(); _userClaimRepository = _unitOfWork.Repository<UserClaim, Guid>(); _userTokenRepository = _unitOfWork.Repository<UserToken, Guid>(); } #endregion #region fields private bool _disposed; private readonly IUnitOfWork _unitOfWork; private readonly IRepository<User, Guid> _userRepository; private readonly IRepository<Role, Guid> _roleRepository; private readonly IRepository<UserRole, Guid> _userRoleRepository; private readonly IRepository<UserLogin, Guid> _userLoginRepository; private readonly IRepository<UserClaim, Guid> _userClaimRepository; private readonly IRepository<UserToken, Guid> _userTokenRepository; #endregion #region Implementation of IQueryableUserStore<User> /// <summary> /// Returns an <see cref="T:System.Linq.IQueryable`1" /> collection of users. /// </summary> /// <value>An <see cref="T:System.Linq.IQueryable`1" /> collection of users.</value> public IQueryable<User> Users => _userRepository.Query(x => x.ID != null); #endregion #region Implementation of IDisposable /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary> public void Dispose() { _disposed = true; } #endregion #region Implementation of IUserStore<User> /// <summary> /// Gets the user identifier for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose identifier should be retrieved.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the identifier for the specified <paramref name="user" />.</returns> public Task<string> GetUserIdAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(ConvertIdToString(user.ID)); } /// <summary> /// Gets the user name for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose name should be retrieved.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the name for the specified <paramref name="user" />.</returns> public Task<string> GetUserNameAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.UserName); } /// <summary> /// Sets the given <paramref name="userName" /> for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose name should be set.</param> /// <param name="userName">The user name to set.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public Task SetUserNameAsync(User user, string userName, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.UserName = userName; return Task.CompletedTask; } /// <summary> /// Gets the normalized user name for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose normalized name should be retrieved.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the normalized user name for the specified <paramref name="user" />.</returns> public Task<string> GetNormalizedUserNameAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.UserName); } /// <summary> /// Sets the given normalized name for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose name should be set.</param> /// <param name="normalizedName">The normalized name to set.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public Task SetNormalizedUserNameAsync(User user, string normalizedName, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.UserName = normalizedName; return Task.CompletedTask; } /// <summary> /// Creates the specified <paramref name="user" /> in the user store. /// </summary> /// <param name="user">The user to create.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the <see cref="T:Microsoft.AspNetCore.Identity.IdentityResult" /> of the creation operation.</returns> public async Task<IdentityResult> CreateAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); await _userRepository.InsertAsync(user); //系統的第一個使用者,自動成為超級管理員 int count = _userRepository.Query(x => x.ID != null).Count(); if (count == 1) { Role adminRole = _roleRepository.Query().FirstOrDefault(); if (adminRole != null) { UserRole userRole = new UserRole() { UserId = user.ID, RoleId = adminRole.ID }; await _userRoleRepository.InsertAsync(userRole); user.IsSystem = true; _userRepository.Update(user); } } //預設角色 Role defaultRole = _roleRepository.Query().FirstOrDefault(m => m.IsDefault); if (defaultRole != null) { UserRole userRole = new UserRole() { UserId = user.ID, RoleId = defaultRole.ID }; await _userRoleRepository.InsertAsync(userRole); } await _unitOfWork.CommitAsync(); return IdentityResult.Success; } /// <summary> /// Updates the specified <paramref name="user" /> in the user store. /// </summary> /// <param name="user">The user to update.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the <see cref="T:Microsoft.AspNetCore.Identity.IdentityResult" /> of the update operation.</returns> public async Task<IdentityResult> UpdateAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); if (user.Email.IsMissing()) { user.EmailConfirmed = false; } if (user.PhoneNumber.IsMissing()) { user.PhoneNumberConfirmed = false; } _userRepository.Update(user); await _unitOfWork.CommitAsync(); return IdentityResult.Success; } /// <summary> /// Deletes the specified <paramref name="user" /> from the user store. /// </summary> /// <param name="user">The user to delete.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the <see cref="T:Microsoft.AspNetCore.Identity.IdentityResult" /> of the update operation.</returns> public async Task<IdentityResult> DeleteAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); if (user.IsSystem) { return new IdentityResult().Failed($"使用者“{user.UserName}”是系統使用者,不能刪除"); } _userRepository.Remove(user); await _unitOfWork.CommitAsync(); return IdentityResult.Success; } /// <summary> /// Finds and returns a user, if any, who has the specified <paramref name="userId" />. /// </summary> /// <param name="userId">The user ID to search for.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the user matching the specified <paramref name="userId" /> if it exists. /// </returns> public Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Guid id = ConvertIdFromString(userId); return Task.FromResult(_userRepository.GetByKey(id)); } /// <summary> /// Finds and returns a user, if any, who has the specified normalized user name. /// </summary> /// <param name="normalizedUserName">The normalized user name to search for.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the user matching the specified <paramref name="normalizedUserName" /> if it exists. /// </returns> public Task<User> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); return Task.FromResult(_userRepository.Query().FirstOrDefault(m => m.UserName == normalizedUserName)); } #endregion #region Implementation of IUserLoginStore<User> /// <summary> /// Adds an external <see cref="T:Microsoft.AspNetCore.Identity.UserLoginInfo" /> to the specified <paramref name="user" />. /// </summary> /// <param name="user">The user to add the login to.</param> /// <param name="login">The external <see cref="T:Microsoft.AspNetCore.Identity.UserLoginInfo" /> to add to the specified <paramref name="user" />.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public async Task AddLoginAsync(User user, UserLoginInfo login, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); Check.NotNull(login, nameof(login)); UserLogin userLogin = new UserLogin() { UserId = user.ID, LoginProvider = login.LoginProvider, ProviderKey = login.ProviderKey, ProviderDisplayName = login.ProviderDisplayName }; await _userLoginRepository.InsertAsync(userLogin); await _unitOfWork.CommitAsync(); } /// <summary> /// Attempts to remove the provided login information from the specified <paramref name="user" />. /// and returns a flag indicating whether the removal succeed or not. /// </summary> /// <param name="user">The user to remove the login information from.</param> /// <param name="loginProvider">The login provide whose information should be removed.</param> /// <param name="providerKey">The key given by the external login provider for the specified user.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public async Task RemoveLoginAsync(User user, string loginProvider, string providerKey, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); Check.NotNullOrEmpty(loginProvider, nameof(loginProvider)); Check.NotNullOrEmpty(providerKey, nameof(providerKey)); _userLoginRepository.Remove(m => m.UserId.Equals(user.ID) && m.LoginProvider == loginProvider && m.ProviderKey == providerKey); await _unitOfWork.CommitAsync(); } /// <summary> /// Retrieves the associated logins for the specified <param ref="user" />. /// </summary> /// <param name="user">The user whose associated logins to retrieve.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task" /> for the asynchronous operation, containing a list of <see cref="T:Microsoft.AspNetCore.Identity.UserLoginInfo" /> for the specified <paramref name="user" />, if any. /// </returns> public Task<IList<UserLoginInfo>> GetLoginsAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); IList<UserLoginInfo> loginInfos = _userLoginRepository.Query(m => m.UserId.Equals(user.ID)).Select(m => new UserLoginInfo(m.LoginProvider, m.ProviderKey, m.ProviderDisplayName)).ToList(); return Task.FromResult(loginInfos); } /// <summary> /// Retrieves the user associated with the specified login provider and login provider key. /// </summary> /// <param name="loginProvider">The login provider who provided the <paramref name="providerKey" />.</param> /// <param name="providerKey">The key provided by the <paramref name="loginProvider" /> to identify a user.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task" /> for the asynchronous operation, containing the user, if any which matched the specified login provider and key. /// </returns> public Task<User> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNullOrEmpty(loginProvider, nameof(loginProvider)); Check.NotNullOrEmpty(providerKey, nameof(providerKey)); Guid userId = _userLoginRepository.Query(m => m.LoginProvider == loginProvider && m.ProviderKey == providerKey) .Select(m => m.UserId).FirstOrDefault(); if (Equals(userId, default(Guid))) { return Task.FromResult(default(User)); } User user = _userRepository.GetByKey(userId); return Task.FromResult(user); } #endregion #region Implementation of IUserClaimStore<User> /// <summary> /// Gets a list of <see cref="T:System.Security.Claims.Claim" />s to be belonging to the specified <paramref name="user" /> as an asynchronous operation. /// </summary> /// <param name="user">The role whose claims to retrieve.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// A <see cref="T:System.Threading.Tasks.Task`1" /> that represents the result of the asynchronous query, a list of <see cref="T:System.Security.Claims.Claim" />s. /// </returns> public Task<IList<Claim>> GetClaimsAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); IList<Claim> claims = _userClaimRepository.Query(m => m.UserId.Equals(user.ID)) .Select(m => new Claim(m.ClaimType, m.ClaimValue)).ToList(); return Task.FromResult(claims); } /// <summary>Add claims to a user as an asynchronous operation.</summary> /// <param name="user">The user to add the claim to.</param> /// <param name="claims">The collection of <see cref="T:System.Security.Claims.Claim" />s to add.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object representing the asynchronous operation.</returns> public async Task AddClaimsAsync(User user, IEnumerable<Claim> claims, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); UserClaim[] userClaims = claims.Select(m => new UserClaim() { UserId = user.ID, ClaimType = m.Type, ClaimValue = m.Value }).ToArray(); await _userClaimRepository.InsertAsync(userClaims); await _unitOfWork.CommitAsync(); } /// <summary> /// Replaces the given <paramref name="claim" /> on the specified <paramref name="user" /> with the <paramref name="newClaim" /> /// </summary> /// <param name="user">The user to replace the claim on.</param> /// <param name="claim">The claim to replace.</param> /// <param name="newClaim">The new claim to replace the existing <paramref name="claim" /> with.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object representing the asynchronous operation.</returns> public Task ReplaceClaimAsync(User user, Claim claim, Claim newClaim, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); List<UserClaim> userClaims = _userClaimRepository.Query(m => m.UserId.Equals(user.ID) && m.ClaimType == claim.Type && m.ClaimValue == claim.Value).ToList(); foreach (UserClaim userClaim in userClaims) { userClaim.ClaimType = newClaim.Type; userClaim.ClaimValue = newClaim.Value; } return Task.CompletedTask; } /// <summary> /// Removes the specified <paramref name="claims" /> from the given <paramref name="user" />. /// </summary> /// <param name="user">The user to remove the specified <paramref name="claims" /> from.</param> /// <param name="claims">A collection of <see cref="T:System.Security.Claims.Claim" />s to remove.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object representing the asynchronous operation.</returns> public async Task RemoveClaimsAsync(User user, IEnumerable<Claim> claims, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); _userClaimRepository.Remove(m => m.UserId.Equals(user.ID) && claims.Any(n => n.Type == m.ClaimType && n.Value == m.ClaimValue)); await _unitOfWork.CommitAsync(); } /// <summary> /// Returns a list of users who contain the specified <see cref="T:System.Security.Claims.Claim" />. /// </summary> /// <param name="claim">The claim to look for.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// A <see cref="T:System.Threading.Tasks.Task`1" /> that represents the result of the asynchronous query, a list of <typeparamref name="User" /> who /// contain the specified claim. /// </returns> public Task<IList<User>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(claim, nameof(claim)); Guid[] userIds = _userClaimRepository.Query(m => m.ClaimType == claim.Type && m.ClaimValue == claim.Value) .Select(m => m.UserId).ToArray(); IList<User> users = _userRepository.Query(m => userIds.Contains(m.ID)).ToList(); return Task.FromResult(users); } #endregion #region Implementation of IUserPasswordStore<User> /// <summary> /// Sets the password hash for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose password hash to set.</param> /// <param name="passwordHash">The password hash to set.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public Task SetPasswordHashAsync(User user, string passwordHash, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.PasswordHash = passwordHash; return Task.CompletedTask; } /// <summary> /// Gets the password hash for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose password hash to retrieve.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, returning the password hash for the specified <paramref name="user" />.</returns> public Task<string> GetPasswordHashAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.PasswordHash); } /// <summary> /// Gets a flag indicating whether the specified <paramref name="user" /> has a password. /// </summary> /// <param name="user">The user to return a flag for, indicating whether they have a password or not.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, returning true if the specified <paramref name="user" /> has a password /// otherwise false. /// </returns> public Task<bool> HasPasswordAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash)); } #endregion #region Implementation of IUserSecurityStampStore<User> /// <summary> /// Sets the provided security <paramref name="stamp" /> for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose security stamp should be set.</param> /// <param name="stamp">The security stamp to set.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.SecurityStamp = stamp; //移除使用者線上快取 //OnlineUserCacheRemoveEventData eventData = new OnlineUserCacheRemoveEventData() { UserNames = new[] { user.UserName } }; //_eventBus.Publish(eventData); return Task.CompletedTask; } /// <summary> /// Get the security stamp for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose security stamp should be set.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the security stamp for the specified <paramref name="user" />.</returns> public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.SecurityStamp); } #endregion #region Implementation of IUserEmailStore<User> /// <summary> /// Sets the <paramref name="email" /> address for a <paramref name="user" />. /// </summary> /// <param name="user">The user whose email should be set.</param> /// <param name="email">The email to set.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object representing the asynchronous operation.</returns> public Task SetEmailAsync(User user, string email, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); Check.NotNull(email, nameof(email)); user.Email = email; return Task.CompletedTask; } /// <summary> /// Gets the email address for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose email should be returned.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object containing the results of the asynchronous operation, the email address for the specified <paramref name="user" />.</returns> public Task<string> GetEmailAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.Email); } /// <summary> /// Gets a flag indicating whether the email address for the specified <paramref name="user" /> has been verified, true if the email address is verified otherwise /// false. /// </summary> /// <param name="user">The user whose email confirmation status should be returned.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The task object containing the results of the asynchronous operation, a flag indicating whether the email address for the specified <paramref name="user" /> /// has been confirmed or not. /// </returns> public Task<bool> GetEmailConfirmedAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.EmailConfirmed); } /// <summary> /// Sets the flag indicating whether the specified <paramref name="user" />'s email address has been confirmed or not. /// </summary> /// <param name="user">The user whose email confirmation status should be set.</param> /// <param name="confirmed">A flag indicating if the email address has been confirmed, true if the address is confirmed otherwise false.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object representing the asynchronous operation.</returns> public Task SetEmailConfirmedAsync(User user, bool confirmed, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.EmailConfirmed = true; return Task.CompletedTask; } /// <summary> /// Gets the user, if any, associated with the specified, normalized email address. /// </summary> /// <param name="normalizedEmail">The normalized email address to return the user for.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The task object containing the results of the asynchronous lookup operation, the user if any associated with the specified normalized email address. /// </returns> public Task<User> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); User user = _userRepository.Query().FirstOrDefault(m => m.Email == normalizedEmail); return Task.FromResult(user); } /// <summary> /// Returns the normalized email for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose email address to retrieve.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// The task object containing the results of the asynchronous lookup operation, the normalized email address if any associated with the specified user. /// </returns> public Task<string> GetNormalizedEmailAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.UserName); } /// <summary> /// Sets the normalized email for the specified <paramref name="user" />. /// </summary> /// <param name="user">The user whose email address to set.</param> /// <param name="normalizedEmail">The normalized email to set for the specified <paramref name="user" />.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The task object representing the asynchronous operation.</returns> public Task SetNormalizedEmailAsync(User user, string normalizedEmail, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.Email = normalizedEmail; return Task.CompletedTask; } #endregion #region Implementation of IUserLockoutStore<User> /// <summary> /// Gets the last <see cref="T:System.DateTimeOffset" /> a user's last lockout expired, if any. /// Any time in the past should be indicates a user is not locked out. /// </summary> /// <param name="user">The user whose lockout date should be retrieved.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns> /// A <see cref="T:System.Threading.Tasks.Task`1" /> that represents the result of the asynchronous query, a <see cref="T:System.DateTimeOffset" /> containing the last time /// a user's lockout expired, if any. /// </returns> public Task<DateTimeOffset?> GetLockoutEndDateAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); return Task.FromResult(user.LockoutEnd); } /// <summary> /// Locks out a user until the specified end date has passed. Setting a end date in the past immediately unlocks a user. /// </summary> /// <param name="user">The user whose lockout date should be set.</param> /// <param name="lockoutEnd">The <see cref="T:System.DateTimeOffset" /> after which the <paramref name="user" />'s lockout should end.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> public Task SetLockoutEndDateAsync(User user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.LockoutEnd = lockoutEnd; return Task.CompletedTask; } /// <summary> /// Records that a failed access has occurred, incrementing the failed access count. /// </summary> /// <param name="user">The user whose cancellation count should be incremented.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the incremented failed access count.</returns> public Task<int> IncrementAccessFailedCountAsync(User user, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); Check.NotNull(user, nameof(user)); user.AccessFailedCount++; return Task.FromResult(user.AccessFailedCount); } /// <summary>Resets a user's failed access count.</summary> /// <param name="user">The user whose failed access count should be reset.</param> /// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param> /// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation.</returns> /// <remarks>This is typically called after the account is successfully accessed.