最近一個項目需要在API里面集成身份驗證,所以選擇了Microsoft.AspNet.Identity.Core,以及Microsoft.AspNet.Identity.Owin來實現,但是在實現過程中發現了需要引入Microsoft.AspNet.Identity.EntityFramework ,導致在代碼內出現了多個EF的上下文,雖然網上到處有改名的方式,但是對於強迫症患者,一個工程里多個上下文始終不能接受。果斷查看有無方案解決
通過獲取源碼發現,Microsoft.AspNet.Identity.EntityFramework只是封裝了EF,完全可以自己來做,下面簡單說明下實現思路。
本文是基於web api5.2+unity+ef來實現
1.通過源碼可以查看的繼承體系
可以看到其核心是Core中的UserManager來操作,並且Microsoft.AspNet.Identity.EntityFramework封裝了EF的上下文和操作的模型。
2.按照需要自定義模型
Microsoft.AspNet.Identity.EntityFramework IdentityRole -> RoleInfo :IRole 只需要繼承IRole即可,默認的左聯按需取舍
IdentityUser -> UserInfo : IUser
自定義 UserRoleInfo,UserClaimInfo,AccountLoginInfo
3.把新的模型添加到自己的EF上下文
通過codefirst在Map里自定義表名字段類型等,想怎么做怎么做。
4.添加身份操作的Store替換Microsoft.AspNet.Identity.EntityFramework里的UserStore和RoleStore
定義一個新的接口,方便注入
/// <summary> /// 身份驗證Store接口 /// </summary> public interface ICustomerIdentityStore : IUserLoginStore<UserInfo, string>, IUserClaimStore<UserInfo, string>, IUserRoleStore<UserInfo, string>, IUserPasswordStore<UserInfo, string>, IUserSecurityStampStore<UserInfo, string>, IQueryableUserStore<UserInfo, string>, IUserEmailStore<UserInfo, string>, IUserPhoneNumberStore<UserInfo, string>, IUserTwoFactorStore<UserInfo, string>, IUserLockoutStore<UserInfo, string>, IUserStore<UserInfo> { }
然后實現其接口,思路的通過注入把上下文的倉儲注入到實現里即可對DB進行操作
5. 自定義身份驗證倉儲接口和實現(樣例代碼)
/// <summary> /// 身份驗證倉儲 /// </summary> public interface IAuthRepository { /// <summary> /// 注冊用戶 /// </summary> /// <param name="userModel"></param> /// <returns></returns> Task<IdentityResult> RegisterUser(UserModel userModel); /// <summary> /// 查找用戶 /// </summary> /// <param name="userName"></param> /// <param name="password"></param> /// <returns></returns> Task<UserInfo> FindUser(string userName, string password); /// <summary> /// 查找AppClient信息 /// </summary> /// <param name="clientId"></param> /// <returns></returns> AppClientInfo FindClient(string clientId); /// <summary> /// 添加Token信息 /// </summary> /// <param name="token"></param> /// <returns></returns> Task<bool> AddRefreshToken(RefreshTokenInfo token); /// <summary> /// 移除token信息 /// </summary> /// <param name="refreshTokenId"></param> /// <returns></returns> Task<bool> RemoveRefreshToken(string refreshTokenId); /// <summary> /// 移除token信息 /// </summary> /// <param name="refreshToken"></param> /// <returns></returns> Task<bool> RemoveRefreshToken(RefreshTokenInfo refreshToken); /// <summary> /// 查找token信息 /// </summary> /// <param name="refreshTokenId"></param> /// <returns></returns> Task<RefreshTokenInfo> FindRefreshToken(string refreshTokenId); /// <summary> /// 查找所有刷新token信息 /// </summary> /// <returns></returns> List<RefreshTokenInfo> GetAllRefreshTokens(); /// <summary> /// 通過登錄信息查找用戶信息 /// </summary> /// <param name="loginInfo"></param> /// <returns></returns> Task<UserInfo> FindAsync(UserLoginInfo loginInfo); /// <summary> /// 創建用戶信息 /// </summary> /// <param name="user"></param> /// <returns></returns> Task<IdentityResult> CreateAsync(UserInfo user); /// <summary> /// 添加用戶登錄信息 /// </summary> /// <param name="userId"></param> /// <param name="login"></param> /// <returns></returns> Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login); }
然后添加其實現
/// <summary> /// 身份驗證倉儲 /// </summary> public class AuthRepository : IAuthRepository { /// <summary> /// 倉儲接口 /// </summary> private readonly IUnitRepository _repository; /// <summary> /// 工作單元 /// </summary> private readonly IUnitOfWork _unitOfWork; /// <summary> /// 用戶管理 /// </summary> private readonly UserManager<UserInfo> _userManager; /// <summary> /// ctor /// </summary> /// <param name="repository"></param> /// <param name="unitOfWork"></param> /// <param name="userStore"></param> public AuthRepository(IUnitRepository repository, IUnitOfWork unitOfWork, ITaurusIdentityStore userStore) { _repository = repository; _unitOfWork = unitOfWork; _userManager = new UserManager<UserInfo>(userStore); } public async Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login) { var result = await _userManager.AddLoginAsync(userId, login); return result; } public async Task<bool> AddRefreshToken(RefreshTokenInfo token) { var existingToken = _repository.FirstOrDefault<RefreshTokenInfo>(r => r.Subject == token.Subject && r.AppClientId == token.AppClientId); if (existingToken != null) { var result = await RemoveRefreshToken(existingToken); } _repository.Insert(token); return _unitOfWork.SaveChanges() > 0; } public async Task<IdentityResult> CreateAsync(UserInfo user) { var result = await _userManager.CreateAsync(user); return result; } public async Task<UserInfo> FindAsync(UserLoginInfo loginInfo) { var user = await _userManager.FindAsync(loginInfo); return user; } public AppClientInfo FindClient(string clientId) { var client = _repository.FirstOrDefault<AppClientInfo>(s => s.Id == clientId); return client; } public Task<RefreshTokenInfo> FindRefreshToken(string refreshTokenId) { var refreshToken = _repository.FirstOrDefault<RefreshTokenInfo>(s => s.TokenId == refreshTokenId); return Task.FromResult(refreshToken); } public async Task<UserInfo> FindUser(string userName, string password) { var user = await _userManager.FindAsync(userName, password); return user; } public List<RefreshTokenInfo> GetAllRefreshTokens() { return _repository.All<RefreshTokenInfo>().ToList(); } public async Task<IdentityResult> RegisterUser(UserModel userModel) { var user = new UserInfo { UserName = userModel.UserName, Id = Guid.NewGuid().ToString(), FullName = "test", CreateTime = DateTime.Now, CreateBy = Guid.Empty.ToString(), UpdateBy = Guid.Empty.ToString(), UpdateTime = DateTime.Now }; var result = await _userManager.CreateAsync(user, userModel.Password); return result; } public Task<bool> RemoveRefreshToken(RefreshTokenInfo refreshToken) { _repository.DeleteItem(refreshToken); var result = _unitOfWork.SaveChanges() > 0; return Task.FromResult(result); } public Task<bool> RemoveRefreshToken(string refreshTokenId) { var refreshToken = _repository.FirstOrDefault<RefreshTokenInfo>(s => s.Id == refreshTokenId); var result = false; if (refreshToken != null) { _repository.DeleteItem(refreshToken); result = _unitOfWork.SaveChanges() > 0; } return Task.FromResult(result); } }
思路是通過注入ICustomerIdentityStore(IUserStore)構造出UserManager實例
6.使用時直接使用IAuthRepository接口就好。
這樣所有的操作都控制自己的代碼里,不再需要去改表名,重新映射字段,維護多個上下文了。
有問題歡迎討論
謝謝