You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AspNetBoilerplate抛出异常后访问失败次数未写入数据库问题

问题

基于AspNetBoilerplate框架开发用户验证密码后取消订阅功能时,遇到以下异常情况:

当前实现代码:

[AbpAuthorize]
public class UserCompaniesManagerAppService : InvoiceAppServiceBase, IApplicationService
{
    public async Task CancelSubscription(CheckPasswordDto input)
    {
        using (CurrentUnitOfWork.SetTenantId(AbpSession.TenantId))
        
        {
            var user = await GetCurrentUserAsync();

            // 验证密码
            if (await UserManager.CheckPasswordAsync(user, input.Password))
            {
                await UserManager.ResetAccessFailedCountAsync(user);
               
                // TODO: 执行取消订阅逻辑
            }
            else
            {
                // 密码错误时记录失败次数
                await UserManager.AccessFailedAsync(user);

                var count = await UserManager.GetAccessFailedCountAsync(user);
                var maxAttempts = await SettingManager.GetSettingValueAsync<int>(
                    AbpZeroSettingNames.UserManagement.UserLockOut.MaxFailedAccessAttemptsBeforeLockout);
               
                throw new UserFriendlyException($"tried {count} left attempts {maxAttempts - count}");
            }
        }
    }
}

抛出UserFriendlyException后,服务器返回的响应格式符合预期,但多次提交错误密码时,失败次数始终保持初始值,且数据库AbpUsers表中未写入失败次数数据。若将方法返回类型改为Task<string>,失败次数统计和账户锁定机制均能正常工作,现需解决抛出异常方式下的次数更新问题。

解决方案
  • 手动提交工作单元:抛出异常会直接终止当前工作单元,导致AccessFailedAsync的更新操作未提交到数据库。在抛出异常前,手动调用CurrentUnitOfWork.SaveChangesAsync()提交变更:
    else
    {
        await UserManager.AccessFailedAsync(user);
        // 手动提交工作单元,确保失败次数写入数据库
        await CurrentUnitOfWork.SaveChangesAsync();
        
        var count = await UserManager.GetAccessFailedCountAsync(user);
        var maxAttempts = await SettingManager.GetSettingValueAsync<int>(
            AbpZeroSettingNames.UserManagement.UserLockOut.MaxFailedAccessAttemptsBeforeLockout);
       
        throw new UserFriendlyException($"tried {count} left attempts {maxAttempts - count}");
    }
    
  • 调整工作单元作用域:using (CurrentUnitOfWork.SetTenantId(...))可能导致工作单元作用域异常,若当前上下文已正确设置租户ID,可尝试移除该语句;若必须保留,需确保所有数据库操作在工作单元内完成并提交后再抛出异常。
  • 确认实体状态变更:检查AccessFailedAsync内部是否正确标记用户实体为修改状态,若未自动标记,可在调用AccessFailedAsync后手动执行await UserManager.UpdateAsync(user),再提交工作单元。

内容的提问来源于stack exchange,提问作者whoiswho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 21:20:10