using Dpz.Core.Service.Mediator.Features.Account.Internal;
namespace Dpz.Core.Service.Mediator.Features.Security.Commands;
/// <summary>
/// 处理当前账号修改密码请求
/// </summary>
public class ChangeAccountPasswordHandler(
IRepository<User> userRepository,
IRepository<UserHistory> userHistoryRepository
) : IRequestHandler<ChangeAccountPasswordRequest, ResponseResult>
{
/// <summary>
/// 验证旧密码,更新新密码并刷新 SecurityStamp
/// </summary>
public async ValueTask<ResponseResult> Handle(
ChangeAccountPasswordRequest request,
CancellationToken cancellationToken
)
{
if (request.Password == request.NewPassword)
{
return ResponseResult.Fail("新密码不能与旧密码一致");
}
var user = await AccountRepositoryHelper.GetUserAsync(
userRepository,
request.Account,
cancellationToken
);
if (user == null)
{
return ResponseResult.Fail("用户不存在");
}
if (!AccountSecurityHelper.VerifyPassword(request.Password, user.Password))
{
return ResponseResult.Fail("当前密码不正确");
}
var newHashedPassword = AccountSecurityHelper.CreatePasswordHash(request.NewPassword);
var newSecurityStamp = AccountSecurityHelper.GenerateSecurityStamp();
await AccountRepositoryHelper.SaveUserHistoryAsync(
userHistoryRepository,
user.Id,
[
AccountRepositoryHelper.Change(nameof(user.Key), user.Key, newSecurityStamp),
AccountRepositoryHelper.Change(
nameof(user.Password),
user.Password,
newHashedPassword
),
],
cancellationToken
);
var update = Builders<User>
.Update.Set(x => x.Password, newHashedPassword)
.Set(x => x.Key, newSecurityStamp)
.Set(x => x.LastUpdateTime, DateTime.Now);
await userRepository.UpdateAsync(x => x.Id == user.Id, update, cancellationToken);
return ResponseResult.Ok();
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
代码解释
这是一个用于处理用户修改密码功能的命令处理器(Command Handler),采用了 CQRS(命令查询职责分离)模式和 MediatR 库的设计风格。
类结构
类定义
public class ChangeAccountPasswordHandler : IRequestHandler<ChangeAccountPasswordRequest, ResponseResult>
- 实现了
IRequestHandler接口,处理ChangeAccountPasswordRequest请求并返回ResponseResult - 使用主构造函数(C# 12新特性)注入依赖
依赖注入
通过构造函数注入两个仓储(Repository):
IRepository<User>- 用户数据仓储IRepository<UserHistory>- 用户历史记录仓储
核心业务流程
1. 密码一致性校验
if (request.Password == request.NewPassword)
return ResponseResult.Fail("新密码不能与旧密码一致");
验证新旧密码是否相同
2. 用户存在性校验
var user = await AccountRepositoryHelper.GetUserAsync(...)
if (user == null)
return ResponseResult.Fail("用户不存在");
通过账号信息查询用户
3. 旧密码验证
if (!AccountSecurityHelper.VerifyPassword(request.Password, user.Password))
return ResponseResult.Fail("当前密码不正确");
验证用户输入的当前密码是否正确
4. 生成新的安全凭证
var newHashedPassword = AccountSecurityHelper.CreatePasswordHash(request.NewPassword);
var newSecurityStamp = AccountSecurityHelper.GenerateSecurityStamp();
- 对新密码进行哈希加密
- 生成新的安全戳(SecurityStamp),用于使现有登录会话失效
5. 保存历史记录
await AccountRepositoryHelper.SaveUserHistoryAsync(
userHistoryRepository,
user.Id,
[
AccountRepositoryHelper.Change(nameof(user.Key), user.Key, newSecurityStamp),
AccountRepositoryHelper.Change(nameof(user.Password), user.Password, newHashedPassword),
],
cancellationToken
);
记录密码和安全戳的变更历史(审计追踪)
6. 更新用户信息
var update = Builders<User>
.Update.Set(x => x.Password, newHashedPassword)
.Set(x => x.Key, newSecurityStamp)
.Set(x => x.LastUpdateTime, DateTime.Now);
await userRepository.UpdateAsync(x => x.Id == user.Id, update, cancellationToken);
使用 MongoDB 风格的 Update Builder 更新:
- 新密码
- 新安全戳
- 最后更新时间
7. 返回成功结果
return ResponseResult.Ok();
技术特点
- 异步编程:全程使用
async/await和ValueTask - 取消令牌:支持操作取消(CancellationToken)
- 安全性:
- 密码哈希存储
- 更新 SecurityStamp 使旧会话失效
- 记录变更历史
- MongoDB 集成:使用
Builders<T>.Update构建更新操作 - 辅助类封装:通过 Helper 类封装通用逻辑,提高代码复用性
AI 正在分析代码…
评论加载中...