最近一个项目需要在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
定义一个新的接口,方便注入
////// 身份验证Store接口 /// public interface ICustomerIdentityStore : IUserLoginStore string>, IUserClaimStore string>, IUserRoleStore string>, IUserPasswordStore string>, IUserSecurityStampStore string>, IQueryableUserStore string>, IUserEmailStore string>, IUserPhoneNumberStore string>, IUserTwoFactorStore string>, IUserLockoutStore string>, IUserStore { }
然后实现其接口,思路的通过注入把上下文的仓储注入到实现里即可对DB进行操作
5. 自定义身份验证仓储接口和实现(样例代码)
////// 身份验证仓储 /// public interface IAuthRepository { /// /// 注册用户 /// /// /// Task RegisterUser(UserModel userModel); /// /// 查找用户 /// /// /// /// Task FindUser(string userName, string password); /// /// 查找AppClient信息 /// /// /// AppClientInfo FindClient(string clientId); /// /// 添加Token信息 /// /// /// Task<bool> AddRefreshToken(RefreshTokenInfo token); /// /// 移除token信息 /// /// /// Task<bool> RemoveRefreshToken(string refreshTokenId); /// /// 移除token信息 /// /// /// Task<bool> RemoveRefreshToken(RefreshTokenInfo refreshToken); /// /// 查找token信息 /// /// /// Task FindRefreshToken(string refreshTokenId); /// /// 查找所有刷新token信息 /// /// List GetAllRefreshTokens(); /// /// 通过登录信息查找用户信息 /// /// /// Task FindAsync(UserLoginInfo loginInfo); /// /// 创建用户信息 /// /// /// Task CreateAsync(UserInfo user); /// /// 添加用户登录信息 /// /// /// /// Task AddLoginAsync(string userId, UserLoginInfo login); }
然后添加其实现
////// 身份验证仓储 /// public class AuthRepository : IAuthRepository { /// /// 仓储接口 /// private readonly IUnitRepository _repository; /// /// 工作单元 /// private readonly IUnitOfWork _unitOfWork; /// /// 用户管理 /// private readonly UserManager _userManager; /// /// ctor /// /// /// /// public AuthRepository(IUnitRepository repository, IUnitOfWork unitOfWork, ITaurusIdentityStore userStore) { _repository = repository; _unitOfWork = unitOfWork; _userManager = new UserManager (userStore); } public async Task 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 (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 CreateAsync(UserInfo user) { var result = await _userManager.CreateAsync(user); return result; } public async Task FindAsync(UserLoginInfo loginInfo) { var user = await _userManager.FindAsync(loginInfo); return user; } public AppClientInfo FindClient(string clientId) { var client = _repository.FirstOrDefault (s => s.Id == clientId); return client; } public Task FindRefreshToken(string refreshTokenId) { var refreshToken = _repository.FirstOrDefault (s => s.TokenId == refreshTokenId); return Task.FromResult(refreshToken); } public async Task FindUser(string userName, string password) { var user = await _userManager.FindAsync(userName, password); return user; } public List GetAllRefreshTokens() { return _repository.All ().ToList(); } public async Task 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 (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接口就好。
这样所有的操作都控制自己的代码里,不再需要去改表名,重新映射字段,维护多个上下文了。
有问题欢迎讨论
谢谢