网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
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;
        }
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

上述代码实现了一个密码迁移服务,主要用于将旧版本的无盐密码迁移到新版本的加盐密码。以下是代码的主要功能和结构的详细解释:

1. 类和构造函数

  • PasswordMigrationService: 这是一个实现了 IPasswordMigrationService 接口的类,负责处理用户密码的迁移。
  • 构造函数: 接受四个依赖项:
    • IRepository<User> userRepository: 用于访问用户数据的仓储接口。
    • IPasswordHashService passwordHashService: 用于处理密码哈希的服务接口。
    • IUserSecurityService userSecurityService: 用于处理用户安全相关操作的服务接口。
    • ILogger<PasswordMigrationService> logger: 用于记录日志的接口。

2. 主要方法

2.1 NeedsMigrationAsync

  • 功能: 检查指定用户是否需要进行密码迁移。
  • 实现:
    • 从数据库中查找用户的密码。
    • 如果用户存在且密码不是新版本的格式,则返回 true,表示需要迁移。

2.2 MigrateUserPasswordAsync

  • 功能: 为指定用户迁移密码。
  • 实现:
    • 查找用户,如果用户不存在,记录警告并返回 false
    • 如果用户的密码已经是新版本,直接返回 true
    • 验证用户输入的明文密码是否与存储的密码匹配。
    • 生成新的加盐密码哈希,并更新数据库中的密码。
    • 更新用户的安全戳(security stamp)。
    • 记录成功或失败的日志。

2.3 BatchMigrateDefaultPasswordUsersAsync

  • 功能: 批量迁移所有使用默认密码的旧版本用户。
  • 实现:
    • 查找所有用户,筛选出需要迁移的用户(即密码不是新版本的)。
    • 遍历这些用户,检查他们是否使用默认密码(如 "123456")。
    • 如果是默认密码,则生成新的加盐密码哈希并更新数据库。
    • 记录每个用户的迁移状态,并在完成后记录总的迁移结果。

2.4 GetMigrationPendingCountAsync

  • 功能: 获取需要迁移的用户数量。
  • 实现:
    • 查找所有用户,统计其中需要迁移的用户数量(即密码不是新版本的)。
    • 返回待迁移用户的数量。

3. 日志记录

  • 代码中使用了 ILogger 记录不同级别的日志,包括信息、警告和错误,帮助开发者跟踪迁移过程中的状态和问题。

总结

这个服务的主要目的是确保用户的密码安全性,通过将旧版本的无盐密码迁移到新版本的加盐密码,增强系统的安全性。它提供了单个用户迁移、批量迁移和统计待迁移用户数量的功能,确保在用户下次登录时能够顺利完成密码的更新。

loading