.Net Core2.2 使用Identity时替换ORM(Dapper替换EF、Oracle替换Sqlserver)层 (二):登入登出

在上一篇博客中项目已经做到访问数据库,但是Identity的核心是身份验证,也就是用户的登入登出,承接之前的项目,继续测试Login方法,发现result是个Failed,也就是登录失败,然后在SysUserDal中发现并没有命中看起来相关的FindByIdAsync方法,就是意味着并没有走到这一步。那么就需要考虑,在中间被封装的这部分功能是如何实现的,为何会返回Failed

https://localhost:XXXXXX/Account/Login

首先观察Login中的PasswordSignInAsync方法,发现该方法被封装,但是现在core所有源码都是开源,所以可以在github中找到 PasswordSignInAsync的所在类SignInManager的源码:

https://github.com/aspnet/AspNetCore/blob/master/src/Identity/Core/src/SignInManager.cs

在上面源码中找到两个PasswordSignInAsync方法:

        /// <summary>
        /// Attempts to sign in the specified <paramref name="user"/> and <paramref name="password"/> combination
        /// as an asynchronous operation.
        /// </summary>
        /// <param name="user">The user to sign in.</param>
        /// <param name="password">The password to attempt to sign in with.</param>
        /// <param name="isPersistent">Flag indicating whether the sign-in cookie should persist after the browser is closed.</param>
        /// <param name="lockoutOnFailure">Flag indicating if the user account should be locked if the sign in fails.</param>
        /// <returns>The task object representing the asynchronous operation containing the <see name="SignInResult"/>
        /// for the sign-in attempt.</returns>
        public virtual async Task<SignInResult> PasswordSignInAsync(TUser user, string password,
            bool isPersistent, bool lockoutOnFailure)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            var attempt = await CheckPasswordSignInAsync(user, password, lockoutOnFailure);
            return attempt.Succeeded
                ? await SignInOrTwoFactorAsync(user, isPersistent)
                : attempt;
        }

        /// <summary>
        /// Attempts to sign in the specified <paramref name="userName"/> and <paramref name="password"/> combination
        /// as an asynchronous operation.
        /// </summary>
        /// <param name="userName">The user name to sign in.</param>
        /// <param name="password">The password to attempt to sign in with.</param>
        /// <param name="isPersistent">Flag indicating whether the sign-in cookie should persist after the browser is closed.</param>
        /// <param name="lockoutOnFailure">Flag indicating if the user account should be locked if the sign in fails.</param>
        /// <returns>The task object representing the asynchronous operation containing the <see name="SignInResult"/>
        /// for the sign-in attempt.</returns>
        public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password,
            bool isPersistent, bool lockoutOnFailure)
        {
            var user = await UserManager.FindByNameAsync(userName);
            if (user == null)
            {
                return SignInResult.Failed;
            }

            return await PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure);
        }

分析我们使用的重载方法,发现了定义上的区别,UserId与UserName的区别,问题在于,执行

var user = await UserManager.FindByNameAsync(userName);

时,我们传入了UserID,但是执行的时候,将UserID当做UserName去数据库检索,所以此时返回了空对象,自然会返回给Account/Login一个Failed结果,此时,如果直接将SysUserDal中的FindByNameAsync方法变更定义,Sql语句中的Where条件直接变更为UserId是最简单的解决办法。

但是这里选用第二种办法,重写SignInManager的PasswordSignInAsync方法,将调用FindByNameAsync变更为FindByIdAsync

一、创建SysUserSignInManager:

   public class SysUserSignInManager : SignInManager<SysUser>
    {
        public SysUserSignInManager(UserManager<SysUser> userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<SysUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor, ILogger<SignInManager<SysUser>> logger, IAuthenticationSchemeProvider schemes) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
        {
        }
        public override async Task<SignInResult> PasswordSignInAsync(SysUser user, string password,
            bool isPersistent, bool lockoutOnFailure)
        {
            if (user == null)
            {
                throw new ArgumentNullException(nameof(user));
            }

            var attempt = await CheckPasswordSignInAsync(user, password, lockoutOnFailure);
            return attempt.Succeeded
                ? await SignInOrTwoFactorAsync(user, isPersistent)
                : attempt;
        }
        public override async Task<SignInResult> PasswordSignInAsync(string userId, string password,
            bool isPersistent, bool lockoutOnFailure)
        {
            var user = await UserManager.FindByIdAsync(userId);
            if (user == null)
            {
                return SignInResult.Failed;
            }

            return await PasswordSignInAsync(user, password, isPersistent, lockoutOnFailure);
        }
        
        private async Task<bool> IsTfaEnabled(SysUser user)
            => UserManager.SupportsUserTwoFactor &&
            await UserManager.GetTwoFactorEnabledAsync(user) &&
            (await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0;
    }

 二、注入到StartUp:


  services.AddTransient<SignInManager<SysUser>, SysUserSignInManager>();

三、此时运行程序,调用Login,发现已经断点已经正确命中的SysUserDal中的FindByIdAsync方法,且返回了数据实体和Succeeded,说明重写生效,此时可以重写SignInManager中的任意方法

四:继续测试GetUser和Logout

https://localhost:XXXXXX/Account/GetUser
https://localhost:XXXXXX/Account/Logout

Logout之后:

至此,Identity简单的登入登出已经实现,当前的项目结构为:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值