<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      ABP登錄返回錯誤次數、鎖定時間

      ABP默認登錄返回錯誤結果時,不會顯示錯誤次數、鎖定時間。為了實現驗證錯誤時返回錯誤次數、鎖定時間,我們需要改造返回接口。
       
      1.定位驗證錯誤的地方:
      修改部分代碼
       1 /// <summary>
       2 /// 獲取登錄結果,如果錯誤則返回錯誤信息
       3 /// </summary>
       4 /// <param name="usernameOrEmailAddress"></param>
       5 /// <param name="password"></param>
       6 /// <param name="tenancyName"></param>
       7 /// <returns></returns>
       8 private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
       9 {
      10     var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
      11     switch (loginResult.Result)
      12     {
      13         case AbpLoginResultType.Success:
      14             return loginResult;
      15         default:
      16             {
      17                 throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName, loginResult.User);
      18             }
      19     }
      20 }

       

      2.修改CreateExceptionForFailedLoginAttempt方法:
       1 public Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName, User user)
       2 {
       3     switch (result)
       4     {
       5         case AbpLoginResultType.Success:
       6             return new Exception("Don't call this method with a success result!");
       7         case AbpLoginResultType.InvalidUserNameOrEmailAddress:
       8         case AbpLoginResultType.InvalidPassword:
       9             //return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPassword"));
      10             return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPasswordRemainErrorTimes{0}", 5 - user.AccessFailedCount));
      11         case AbpLoginResultType.InvalidTenancyName:
      12             return new UserFriendlyException(L("LoginFailed"), L("ThereIsNoTenantDefinedWithName{0}", tenancyName));
      13         case AbpLoginResultType.TenantIsNotActive:
      14             return new UserFriendlyException(L("LoginFailed"), L("TenantIsNotActive", tenancyName));
      15         case AbpLoginResultType.UserIsNotActive:
      16             return new UserFriendlyException(L("LoginFailed"), L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
      17         case AbpLoginResultType.UserEmailIsNotConfirmed:
      18             return new UserFriendlyException(L("LoginFailed"), L("UserEmailIsNotConfirmedAndCanNotLogin"));
      19         case AbpLoginResultType.LockedOut:
      20             //todo 此處后期需要改為客戶端獲取UTC時間后,格式化展示,以符合國際化
      21             return new UserFriendlyException(L("LoginFailed"), L("UserLockedOutMessageUntilTime{0}", user.LockoutEndDateUtc?.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")));
      22         default: // Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
      23             Logger.Warn("Unhandled login fail reason: " + result);
      24             return new UserFriendlyException(L("LoginFailed"));
      25     }
      26 }

       

       
      3.原以為這樣就可以使用了,調試時候發現數據庫更新了,但是loginResult.User的結果不是最新的。試過各種方式:從UserStore、IRepository<User, long>、DBContext中獲取,都是和loginResult.User一致,但是和數據庫不一致。
      4.后續定位問題,發現執行完
      var loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);

      后,數據庫就更新了。為了弄清楚原理只能去解讀ABP源碼了。

      5.一路追查,后來定位到如下TryLockOutAsync方法,在AbpLogInManager類中
       
      protected virtual async Task<bool> TryLockOutAsync(int? tenantId, long userId)
      {
          using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.Suppress))
          {
              using (UnitOfWorkManager.Current.SetTenantId(tenantId))
              {
                  var user = await UserManager.FindByIdAsync(userId.ToString());
      
                  (await UserManager.AccessFailedAsync(user)).CheckErrors();
      
                  var isLockOut = await UserManager.IsLockedOutAsync(user);
      
                  await UnitOfWorkManager.Current.SaveChangesAsync();
      
                  await uow.CompleteAsync();
      
                  return isLockOut;
              }
          }
      }

       

      大家可以看到此方法會重新從UserManager中獲取user對象,并返回isLockOut。而UserManager.AccessFailedAsync如下:
       1 /// <summary>
       2 /// Increments the access failed count for the user as an asynchronous operation.
       3 /// If the failed access account is greater than or equal to the configured maximum number of attempts,
       4 /// the user will be locked out for the configured lockout time span.
       5 /// </summary>
       6 /// <param name="user">The user whose failed access count to increment.</param>
       7 /// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the operation.</returns>
       8 public virtual async Task<IdentityResult> AccessFailedAsync(TUser user)
       9 {
      10     ThrowIfDisposed();
      11     var store = GetUserLockoutStore();
      12     if (user == null)
      13     {
      14         throw new ArgumentNullException(nameof(user));
      15     }
      16 
      17     // If this puts the user over the threshold for lockout, lock them out and reset the access failed count
      18     var count = await store.IncrementAccessFailedCountAsync(user, CancellationToken);
      19     if (count < Options.Lockout.MaxFailedAccessAttempts)
      20     {
      21         return await UpdateUserAsync(user);
      22     }
      23     Logger.LogWarning(12, "User is locked out.");
      24     await store.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(Options.Lockout.DefaultLockoutTimeSpan),
      25         CancellationToken);
      26     await store.ResetAccessFailedCountAsync(user, CancellationToken);
      27     return await UpdateUserAsync(user);
      28 }

      會執行IncrementAccessFailedCountAsyncUpdateUserAsync。如果成功執行,user會增加一次驗證失敗的統計并保存到數據庫中。

      TryLockOutAsync被AbpLogInManager類中的LoginAsyncInternal方法所調用。我們需要改寫此方法。
       1 protected virtual async Task<AbpLoginResult<TTenant, TUser>> LoginAsyncInternal(string userNameOrEmailAddress, string plainPassword, string tenancyName, bool shouldLockout)
       2 {
       3     if (userNameOrEmailAddress.IsNullOrEmpty())
       4     {
       5         throw new ArgumentNullException(nameof(userNameOrEmailAddress));
       6     }
       7 
       8     if (plainPassword.IsNullOrEmpty())
       9     {
      10         throw new ArgumentNullException(nameof(plainPassword));
      11     }
      12 
      13     //Get and check tenant
      14     TTenant tenant = null;
      15     using (UnitOfWorkManager.Current.SetTenantId(null))
      16     {
      17         if (!MultiTenancyConfig.IsEnabled)
      18         {
      19             tenant = await GetDefaultTenantAsync();
      20         }
      21         else if (!string.IsNullOrWhiteSpace(tenancyName))
      22         {
      23             tenant = await TenantRepository.FirstOrDefaultAsync(t => t.TenancyName == tenancyName);
      24             if (tenant == null)
      25             {
      26                 return new AbpLoginResult<TTenant, TUser>(AbpLoginResultType.InvalidTenancyName);
      27             }
      28 
      29             if (!tenant.IsActive)
      30             {
      31                 return new AbpLoginResult<TTenant, TUser>(AbpLoginResultType.TenantIsNotActive, tenant);
      32             }
      33         }
      34     }
      35 
      36     var tenantId = tenant == null ? (int?)null : tenant.Id;
      37     using (UnitOfWorkManager.Current.SetTenantId(tenantId))
      38     {
      39         await UserManager.InitializeOptionsAsync(tenantId);
      40 
      41         //TryLoginFromExternalAuthenticationSources method may create the user, that's why we are calling it before AbpUserStore.FindByNameOrEmailAsync
      42         var loggedInFromExternalSource = await TryLoginFromExternalAuthenticationSourcesAsync(userNameOrEmailAddress, plainPassword, tenant);
      43 
      44         var user = await UserManager.FindByNameOrEmailAsync(tenantId, userNameOrEmailAddress);
      45         if (user == null)
      46         {
      47             return new AbpLoginResult<TTenant, TUser>(AbpLoginResultType.InvalidUserNameOrEmailAddress, tenant);
      48         }
      49 
      50         if (await UserManager.IsLockedOutAsync(user))
      51         {
      52             return new AbpLoginResult<TTenant, TUser>(AbpLoginResultType.LockedOut, tenant, user);
      53         }
      54 
      55         if (!loggedInFromExternalSource)
      56         {
      57             if (!await UserManager.CheckPasswordAsync(user, plainPassword))
      58             {
      59                 if (shouldLockout)
      60                 {
      61                     if (await TryLockOutAsync(tenantId, user.Id))
      62                     {
      63                         return new AbpLoginResult<TTenant, TUser>(AbpLoginResultType.LockedOut, tenant, user);
      64                     }
      65                 }
      66 
      67                 return new AbpLoginResult<TTenant, TUser>(AbpLoginResultType.InvalidPassword, tenant, user);
      68             }
      69 
      70             await UserManager.ResetAccessFailedCountAsync(user);
      71         }
      72 
      73         return await CreateLoginResultAsync(user, tenant);
      74     }
      75 }

       

      6.在LogInManager中override LoginAsyncInternal方法,并添加新的TryLockOutAsync方法,傳入User引用,在uow成功提交后,賦值AccessFailedCount 和 LockoutEndDateUtc 屬性。這樣loginResult.User即可保持最新。
       
      public class LogInManager : AbpLogInManager<Tenant, Role, User>
      {
          public LogInManager(
              UserManager userManager, 
              IMultiTenancyConfig multiTenancyConfig,
              IRepository<Tenant> tenantRepository,
              IUnitOfWorkManager unitOfWorkManager,
              ISettingManager settingManager, 
              IRepository<UserLoginAttempt, long> userLoginAttemptRepository, 
              IUserManagementConfig userManagementConfig,
              IIocResolver iocResolver,
              IPasswordHasher<User> passwordHasher, 
              RoleManager roleManager,
              UserClaimsPrincipalFactory claimsPrincipalFactory) 
              : base(
                    userManager, 
                    multiTenancyConfig,
                    tenantRepository, 
                    unitOfWorkManager, 
                    settingManager, 
                    userLoginAttemptRepository, 
                    userManagementConfig, 
                    iocResolver, 
                    passwordHasher, 
                    roleManager, 
                    claimsPrincipalFactory)
          {
          }
      
          protected override async Task<AbpLoginResult<Tenant, User>> LoginAsyncInternal(string userNameOrEmailAddress, string plainPassword, string tenancyName, bool shouldLockout)
          {
              //return base.LoginAsyncInternal(userNameOrEmailAddress, plainPassword, tenancyName, shouldLockout);
              if (userNameOrEmailAddress.IsNullOrEmpty())
              {
                  throw new ArgumentNullException(nameof(userNameOrEmailAddress));
              }
      
              if (plainPassword.IsNullOrEmpty())
              {
                  throw new ArgumentNullException(nameof(plainPassword));
              }
      
              //Get and check tenant
              Tenant tenant = null;
              using (UnitOfWorkManager.Current.SetTenantId(null))
              {
                  if (!MultiTenancyConfig.IsEnabled)
                  {
                      tenant = await GetDefaultTenantAsync();
                  }
                  else if (!string.IsNullOrWhiteSpace(tenancyName))
                  {
                      tenant = await TenantRepository.FirstOrDefaultAsync(t => t.TenancyName == tenancyName);
                      if (tenant == null)
                      {
                          return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidTenancyName);
                      }
      
                      if (!tenant.IsActive)
                      {
                          return new AbpLoginResult<Tenant, User>(AbpLoginResultType.TenantIsNotActive, tenant);
                      }
                  }
              }
      
              var tenantId = tenant == null ? (int?)null : tenant.Id;
              using (UnitOfWorkManager.Current.SetTenantId(tenantId))
              {
                  await UserManager.InitializeOptionsAsync(tenantId);
      
                  //TryLoginFromExternalAuthenticationSources method may create the user, that's why we are calling it before AbpUserStore.FindByNameOrEmailAsync
                  var loggedInFromExternalSource = await TryLoginFromExternalAuthenticationSourcesAsync(userNameOrEmailAddress, plainPassword, tenant);
      
                  var user = await UserManager.FindByNameOrEmailAsync(tenantId, userNameOrEmailAddress);
                  if (user == null)
                  {
                      return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidUserNameOrEmailAddress, tenant);
                  }
      
                  if (await UserManager.IsLockedOutAsync(user))
                  {
                      return new AbpLoginResult<Tenant, User>(AbpLoginResultType.LockedOut, tenant, user);
                  }
      
                  if (!loggedInFromExternalSource)
                  {
                      if (!await UserManager.CheckPasswordAsync(user, plainPassword))
                      {
                          if (shouldLockout)
                          {
                              //此處返回修改后的結果,可能會對數據產生影響
                              if (await TryLockOutAsync(tenantId, user))
                              {
                                  return new AbpLoginResult<Tenant, User>(AbpLoginResultType.LockedOut, tenant, user);
                              }
                          }
      
                          return new AbpLoginResult<Tenant, User>(AbpLoginResultType.InvalidPassword, tenant, user);
                      }
      
                      await UserManager.ResetAccessFailedCountAsync(user);
                  }
      
                  return await CreateLoginResultAsync(user, tenant);
              }
          }
      
          /// <summary>
          /// 嘗試鎖定用戶,并更新其狀態
          /// </summary>
          /// <param name="tenantId"></param>
          /// <param name="inputUser"></param>
          /// <returns></returns>
          protected  async Task<bool> TryLockOutAsync(int? tenantId, User inputUser)
          {
              using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.Suppress))
              {
                  using (UnitOfWorkManager.Current.SetTenantId(tenantId))
                  {
                      var user = await UserManager.FindByIdAsync(inputUser.Id.ToString());
      
                      (await UserManager.AccessFailedAsync(user)).CheckErrors();
      
                      var isLockOut = await UserManager.IsLockedOutAsync(user);
      
                      await UnitOfWorkManager.Current.SaveChangesAsync();
      
                      await uow.CompleteAsync();
                      inputUser.AccessFailedCount = user.AccessFailedCount;
                      inputUser.LockoutEndDateUtc = user.LockoutEndDateUtc;
                      return isLockOut;
                  }
              }
              //return base.TryLockOutAsync(tenantId, userId);
          }
      }
       

      posted @ 2020-11-26 14:20  天命小豬  閱讀(2004)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 精品素人AV无码不卡在线观看| 夜夜影院未满十八勿进| 亚洲精品自拍区在线观看| 亚洲avav天堂av在线网爱情| 日韩成人午夜精品久久高潮| 人妻少妇无码精品专区| 亚洲va中文字幕无码久久不卡| 韩国午夜福利片在线观看| 亚洲国产成人精品综合色| 国产精品色内内在线播放| 亚洲欧美国产日韩天堂区| 最新的国产成人精品2020| 午夜DY888国产精品影院| 亚洲色大成网站www久久九九| 国产超碰人人爽人人做| 国产免费高清69式视频在线观看 | 人妻少妇88久久中文字幕| 日韩中文字幕一区二区不卡| 亚洲aⅴ无码专区在线观看春色| 国产美女高潮流白浆视频| a级亚洲片精品久久久久久久| 日日躁狠狠躁狠狠爱| 读书| 人人爽人人澡人人人妻| 成年女人片免费视频播放A| 性色av免费观看| 午夜爽爽爽男女污污污网站| 日本午夜精品一区二区三区电影| 亚洲va韩国va欧美va| 欧美精欧美乱码一二三四区| 蜜臀视频在线观看一区二区| 国产欧美日韩高清在线不卡| 免费现黄频在线观看国产| 国产精品久久无码不卡黑寡妇 | 国产成人a在线观看视频免费| 色婷婷日日躁夜夜躁| 日韩精品亚洲精品第一页| 亚洲精品人成网线在播放VA | 韩国午夜福利片在线观看| 亚洲av高清一区二区三| a4yy私人毛片|