网站首页 网站源码
namespace Dpz.Core.Service.RepositoryServiceImpl;
/// <summary>
/// 密码迁移服务实现
/// 用于将旧版本无盐密码迁移到新版本加盐密码
/// </summary>
public class PasswordMigrationService(
IRepository<User> userRepository,
IPasswordHashService passwordHashService,
IUserSecurityService userSecurityService,
ILogger<PasswordMigrationService> logger
) : IPasswordMigrationService
{
/// <summary>
/// 检查用户是否需要密码迁移
/// </summary>
public async Task<bool> NeedsMigrationAsync(string userId)
{
var user = await userRepository
.Collection.Find(x => x.Id == userId)
.Project(x => new { x.Password })
.FirstOrDefaultAsync();
return user != null && !passwordHashService.IsNewVersionPassword(user.Password);
}
/// <summary>
/// 为单个用户迁移密码(在用户下次登录时自动执行)
/// </summary>
public async Task<bool> MigrateUserPasswordAsync(string userId, string plainPassword)
{
try
{
var user = await userRepository
.Collection.Find(x => x.Id == userId)
.FirstOrDefaultAsync();
if (user == null)
{
logger.LogWarning("尝试迁移不存在的用户密码: {UserId}", userId);
return false;
}
// 如果已经是新版本密码,无需迁移
if (passwordHashService.IsNewVersionPassword(user.Password))
{
return true;
}
// 验证当前密码是否正确(使用智能验证)
if (!passwordHashService.VerifyPassword(userId, plainPassword, user.Password))
{
logger.LogWarning("密码迁移失败,密码不匹配: {UserId}", userId);
return false;
}
// 生成新的BCrypt密码哈希
var newHashedPassword = passwordHashService.CreatePasswordHash(plainPassword);
// 更新数据库
var update = Builders<User>
.Update.Set(x => x.Password, newHashedPassword)
.Set(x => x.LastUpdateTime, DateTime.Now);
var result = await userRepository.UpdateAsync(x => x.Id == userId, update);
await userSecurityService.UpdateUserSecurityStampAsync(userId, "密码迁移");
if (result.ModifiedCount > 0)
{
logger.LogInformation("用户 {UserId} 的密码已成功迁移到新版本", userId);
return true;
}
logger.LogWarning("用户 {UserId} 的密码迁移失败,数据库更新失败", userId);
return false;
}
catch (Exception ex)
{
logger.LogError(ex, "迁移用户 {UserId} 密码时发生错误", userId);
return false;
}
}
/// <summary>
/// 批量迁移所有使用默认密码的旧版本用户
/// </summary>
public async Task<int> BatchMigrateDefaultPasswordUsersAsync()
{
try
{
logger.LogInformation("开始批量迁移默认密码用户");
// 查找所有需要迁移的用户(非BCrypt格式的密码)
var allUsers = await userRepository
.Collection.Find(Builders<User>.Filter.Empty)
.ToListAsync();
var oldVersionUsers = allUsers
.Where(u => !passwordHashService.IsNewVersionPassword(u.Password))
.ToList();
var migratedCount = 0;
var defaultPassword = "123456";
foreach (var user in oldVersionUsers)
{
try
{
// 检查是否使用默认密码
if (
!passwordHashService.VerifyPasswordMD5(
user.Id,
defaultPassword,
user.Password
)
)
{
logger.LogDebug("用户 {UserId} 未使用默认密码,跳过自动迁移", user.Id);
continue;
}
// 生成新的BCrypt密码哈希
var newHashedPassword = passwordHashService.CreatePasswordHash(defaultPassword);
// 更新数据库
var update = Builders<User>
.Update.Set(x => x.Password, newHashedPassword)
.Set(x => x.LastUpdateTime, DateTime.Now);
var result = await userRepository.UpdateAsync(x => x.Id == user.Id, update);
await userSecurityService.UpdateUserSecurityStampAsync(user.Id, "密码迁移");
if (result.ModifiedCount > 0)
{
migratedCount++;
logger.LogDebug("用户 {UserId} 的默认密码已迁移", user.Id);
}
}
catch (Exception ex)
{
logger.LogError(ex, "迁移用户 {UserId} 的默认密码时发生错误", user.Id);
}
}
logger.LogInformation(
"批量迁移完成,成功迁移 {MigratedCount}/{TotalCount} 个默认密码用户",
migratedCount,
oldVersionUsers.Count
);
return migratedCount;
}
catch (Exception ex)
{
logger.LogError(ex, "批量迁移默认密码用户时发生错误");
return 0;
}
}
/// <summary>
/// 获取需要迁移的用户统计信息
/// </summary>
public async Task<int> GetMigrationPendingCountAsync()
{
try
{
var allUsers = await userRepository
.Collection.Find(Builders<User>.Filter.Empty)
.Project(x => new { x.Password })
.ToListAsync();
var pendingCount = allUsers.Count(u =>
!passwordHashService.IsNewVersionPassword(u.Password)
);
return pendingCount;
}
catch (Exception ex)
{
logger.LogError(ex, "获取待迁移用户数量时发生错误");
return 0;
}
}
}
上述代码实现了一个密码迁移服务,主要用于将旧版本的无盐密码迁移到新版本的加盐密码。以下是代码的主要功能和结构的详细解释:
IPasswordMigrationService 接口的类,负责处理用户密码的迁移。IRepository<User> userRepository: 用于访问用户数据的仓储接口。IPasswordHashService passwordHashService: 用于处理密码哈希的服务接口。IUserSecurityService userSecurityService: 用于处理用户安全相关操作的服务接口。ILogger<PasswordMigrationService> logger: 用于记录日志的接口。NeedsMigrationAsynctrue,表示需要迁移。MigrateUserPasswordAsyncfalse。true。BatchMigrateDefaultPasswordUsersAsyncGetMigrationPendingCountAsyncILogger 记录不同级别的日志,包括信息、警告和错误,帮助开发者跟踪迁移过程中的状态和问题。这个服务的主要目的是确保用户的密码安全性,通过将旧版本的无盐密码迁移到新版本的加盐密码,增强系统的安全性。它提供了单个用户迁移、批量迁移和统计待迁移用户数量的功能,确保在用户下次登录时能够顺利完成密码的更新。
