還在為身份驗證引入的Microsoft.AspNet.Identity.EntityFramework導致多上下文,生成的DB改名困擾嗎?


  最近一個項目需要在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接口就好。

  這樣所有的操作都控制自己的代碼里,不再需要去改表名,重新映射字段,維護多個上下文了。

有問題歡迎討論

謝謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM