634 lines
25 KiB
C#
634 lines
25 KiB
C#
using Microsoft.Extensions.Logging;
|
||
using OrpaonVision.Core.Results;
|
||
using OrpaonVision.Model.Security;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
|
||
namespace OrpaonVision.ConfigApp.Infrastructure.Services;
|
||
|
||
/// <summary>
|
||
/// 用户管理服务实现。
|
||
/// </summary>
|
||
public sealed class UserService : IUserService
|
||
{
|
||
private readonly ILogger<UserService> _logger;
|
||
private readonly List<UserModel> _users;
|
||
private readonly Dictionary<string, int> _loginFailCounts;
|
||
|
||
/// <summary>
|
||
/// 构造函数。
|
||
/// </summary>
|
||
public UserService(ILogger<UserService> logger)
|
||
{
|
||
_logger = logger;
|
||
_users = new List<UserModel>();
|
||
_loginFailCounts = new Dictionary<string, int>();
|
||
|
||
// 初始化示例数据
|
||
InitializeSampleData();
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<UserModel> CreateUser(UserModel user)
|
||
{
|
||
try
|
||
{
|
||
if (user == null)
|
||
{
|
||
return Result<UserModel>.Fail("USER_NULL", "用户不能为空。");
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(user.Username))
|
||
{
|
||
return Result<UserModel>.Fail("USERNAME_REQUIRED", "用户名不能为空。");
|
||
}
|
||
|
||
// 检查用户名是否已存在
|
||
if (_users.Any(u => u.Username.Equals(user.Username, StringComparison.OrdinalIgnoreCase)))
|
||
{
|
||
return Result<UserModel>.Fail("USERNAME_EXISTS", "用户名已存在。");
|
||
}
|
||
|
||
_logger.LogInformation("正在创建用户: {Username}", user.Username);
|
||
|
||
// 生成密码哈希
|
||
var (hash, salt) = GeneratePasswordHash(user.PasswordHash);
|
||
|
||
user.Id = Guid.NewGuid();
|
||
user.PasswordHash = hash;
|
||
user.PasswordSalt = salt;
|
||
user.Status = UserStatus.Enabled;
|
||
user.IsFirstLogin = true;
|
||
user.LoginFailedCount = 0;
|
||
user.CreatedAtUtc = DateTime.UtcNow;
|
||
user.UpdatedAtUtc = DateTime.UtcNow;
|
||
|
||
_users.Add(user);
|
||
|
||
_logger.LogInformation("用户创建成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result<UserModel>.Success(user, message: "用户创建成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "创建用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "CREATE_USER_FAILED", "创建用户失败。", traceId);
|
||
return Result<UserModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<UserModel> UpdateUser(UserModel user)
|
||
{
|
||
try
|
||
{
|
||
if (user == null)
|
||
{
|
||
return Result<UserModel>.Fail("USER_NULL", "用户不能为空。");
|
||
}
|
||
|
||
var existingUser = _users.FirstOrDefault(u => u.Id == user.Id);
|
||
if (existingUser == null)
|
||
{
|
||
return Result<UserModel>.Fail("USER_NOT_FOUND", $"未找到ID为 {user.Id} 的用户。");
|
||
}
|
||
|
||
_logger.LogInformation("正在更新用户: {UserId} - {Username}", user.Id, user.Username);
|
||
|
||
// 更新属性(不包含密码相关字段)
|
||
existingUser.DisplayName = user.DisplayName;
|
||
existingUser.Email = user.Email;
|
||
existingUser.PhoneNumber = user.PhoneNumber;
|
||
existingUser.Remark = user.Remark;
|
||
existingUser.UpdatedAtUtc = DateTime.UtcNow;
|
||
existingUser.UpdatedBy = user.UpdatedBy;
|
||
|
||
_logger.LogInformation("用户更新成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result<UserModel>.Success(existingUser, message: "用户更新成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "更新用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "UPDATE_USER_FAILED", "更新用户失败。", traceId);
|
||
return Result<UserModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result DeleteUser(Guid userId)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
_logger.LogInformation("正在删除用户: {UserId} - {Username}", user.Id, user.Username);
|
||
|
||
// 软删除
|
||
user.Status = UserStatus.Deleted;
|
||
user.UpdatedAtUtc = DateTime.UtcNow;
|
||
user.UpdatedBy = "System";
|
||
|
||
_logger.LogInformation("用户删除成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result.Success(message: "用户删除成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "删除用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "DELETE_USER_FAILED", "删除用户失败。", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<UserModel> GetUserById(Guid userId)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result<UserModel>.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
// 清除敏感信息
|
||
var safeUser = CloneUserWithoutSensitiveData(user);
|
||
return Result<UserModel>.Success(safeUser, message: "获取用户成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_USER_FAILED", "获取用户失败。", traceId);
|
||
return Result<UserModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<UserModel> GetUserByUsername(string username)
|
||
{
|
||
try
|
||
{
|
||
if (string.IsNullOrWhiteSpace(username))
|
||
{
|
||
return Result<UserModel>.Fail("USERNAME_REQUIRED", "用户名不能为空。");
|
||
}
|
||
|
||
var user = _users.FirstOrDefault(u => u.Username.Equals(username, StringComparison.OrdinalIgnoreCase));
|
||
if (user == null)
|
||
{
|
||
return Result<UserModel>.Fail("USER_NOT_FOUND", $"未找到用户名为 {username} 的用户。");
|
||
}
|
||
|
||
// 清除敏感信息
|
||
var safeUser = CloneUserWithoutSensitiveData(user);
|
||
return Result<UserModel>.Success(safeUser, message: "获取用户成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_USER_FAILED", "获取用户失败。", traceId);
|
||
return Result<UserModel>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<bool> VerifyPassword(string username, string password)
|
||
{
|
||
try
|
||
{
|
||
if (string.IsNullOrWhiteSpace(username))
|
||
{
|
||
return Result<bool>.Fail("USERNAME_REQUIRED", "用户名不能为空。");
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(password))
|
||
{
|
||
return Result<bool>.Fail("PASSWORD_REQUIRED", "密码不能为空。");
|
||
}
|
||
|
||
var user = _users.FirstOrDefault(u => u.Username.Equals(username, StringComparison.OrdinalIgnoreCase));
|
||
if (user == null)
|
||
{
|
||
return Result<bool>.Fail("USER_NOT_FOUND", $"未找到用户名为 {username} 的用户。");
|
||
}
|
||
|
||
if (user.Status != UserStatus.Enabled)
|
||
{
|
||
return Result<bool>.Fail("USER_INACTIVE", "用户已被禁用。");
|
||
}
|
||
|
||
// 检查登录失败次数
|
||
if (_loginFailCounts.TryGetValue(username, out var failCount) && failCount >= 5)
|
||
{
|
||
return Result<bool>.Fail("ACCOUNT_LOCKED", "账户已被锁定,请联系管理员。");
|
||
}
|
||
|
||
// 验证密码(简化版本,实际应该使用哈希比较)
|
||
var isPasswordValid = VerifyPasswordHash(password, user.PasswordHash);
|
||
|
||
if (isPasswordValid)
|
||
{
|
||
// 登录成功,清除失败计数
|
||
_loginFailCounts.Remove(username);
|
||
_logger.LogInformation("用户 {Username} 登录成功", username);
|
||
return Result<bool>.Success(true, "登录成功。");
|
||
}
|
||
else
|
||
{
|
||
// 登录失败,增加失败计数
|
||
_loginFailCounts[username] = _loginFailCounts.GetValueOrDefault(username, 0) + 1;
|
||
_logger.LogWarning("用户 {Username} 登录失败,当前失败次数: {FailCount}", username, _loginFailCounts[username]);
|
||
|
||
var remainingAttempts = 5 - _loginFailCounts[username];
|
||
var message = remainingAttempts > 0
|
||
? $"密码错误,还有 {remainingAttempts} 次尝试机会。"
|
||
: "账户已被锁定,请联系管理员。";
|
||
|
||
return Result<bool>.Fail("PASSWORD_INCORRECT", message);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "验证密码失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "VERIFY_PASSWORD_FAILED", "验证密码失败。", traceId);
|
||
return Result<bool>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<PagedResult<UserModel>> GetUserPagedList(int pageIndex = 1, int pageSize = 20, UserStatus? status = null, string? keyword = null)
|
||
{
|
||
try
|
||
{
|
||
var query = _users.Where(u => u.Status != UserStatus.Deleted).AsQueryable();
|
||
|
||
// 状态过滤
|
||
if (status.HasValue)
|
||
{
|
||
query = query.Where(u => u.Status == status.Value);
|
||
}
|
||
|
||
// 关键词搜索
|
||
if (!string.IsNullOrWhiteSpace(keyword))
|
||
{
|
||
query = query.Where(u =>
|
||
u.Username.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
|
||
u.DisplayName.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
|
||
(u.Email != null && u.Email.Contains(keyword, StringComparison.OrdinalIgnoreCase)));
|
||
}
|
||
|
||
// 排序
|
||
query = query.OrderByDescending(u => u.CreatedAtUtc);
|
||
|
||
var totalCount = query.Count();
|
||
var items = query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
|
||
|
||
// 清除敏感信息
|
||
var safeItems = items.Select(CloneUserWithoutSensitiveData).ToList();
|
||
|
||
var pagedResult = PagedResult<UserModel>.Success(safeItems, totalCount, pageIndex, pageSize);
|
||
|
||
return Result<PagedResult<UserModel>>.Success(pagedResult, message: "获取用户列表成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取用户列表失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_USER_LIST_FAILED", "获取用户列表失败。", traceId);
|
||
return Result<PagedResult<UserModel>>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result EnableUser(Guid userId, string enabledBy)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
_logger.LogInformation("正在启用用户: {UserId} - {Username}", user.Id, user.Username);
|
||
|
||
user.Status = UserStatus.Enabled;
|
||
user.UpdatedAtUtc = DateTime.UtcNow;
|
||
user.UpdatedBy = enabledBy;
|
||
|
||
_logger.LogInformation("用户启用成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result.Success(message: "用户启用成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "启用用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "ENABLE_USER_FAILED", "启用用户失败。", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result DisableUser(Guid userId, string disabledBy)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
_logger.LogInformation("正在禁用用户: {UserId} - {Username}", user.Id, user.Username);
|
||
|
||
user.Status = UserStatus.Disabled;
|
||
user.UpdatedAtUtc = DateTime.UtcNow;
|
||
user.UpdatedBy = disabledBy;
|
||
|
||
_logger.LogInformation("用户禁用成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result.Success(message: "用户禁用成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "禁用用户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "DISABLE_USER_FAILED", "禁用用户失败。", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result ResetPassword(Guid userId, string newPassword, string resetBy)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(newPassword))
|
||
{
|
||
return Result.Fail("PASSWORD_REQUIRED", "新密码不能为空。");
|
||
}
|
||
|
||
_logger.LogInformation("正在重置用户密码: {UserId} - {Username}", user.Id, user.Username);
|
||
|
||
// 生成新密码哈希
|
||
var (hash, salt) = GeneratePasswordHash(newPassword);
|
||
|
||
user.PasswordHash = hash;
|
||
user.PasswordSalt = salt;
|
||
user.IsFirstLogin = true;
|
||
user.LoginFailedCount = 0;
|
||
user.LockedUntilUtc = null;
|
||
user.UpdatedAtUtc = DateTime.UtcNow;
|
||
user.UpdatedBy = resetBy;
|
||
|
||
_logger.LogInformation("用户密码重置成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result.Success(message: "用户密码重置成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "重置用户密码失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "RESET_PASSWORD_FAILED", "重置用户密码失败。", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result UnlockUser(Guid userId, string unlockedBy)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
_logger.LogInformation("正在解锁用户账户: {UserId} - {Username}", user.Id, user.Username);
|
||
|
||
user.Status = UserStatus.Enabled;
|
||
user.LoginFailedCount = 0;
|
||
user.LockedUntilUtc = null;
|
||
user.UpdatedAtUtc = DateTime.UtcNow;
|
||
user.UpdatedBy = unlockedBy;
|
||
|
||
// 清除登录失败计数
|
||
_loginFailCounts.Remove(user.Username);
|
||
|
||
_logger.LogInformation("用户账户解锁成功: {UserId} - {Username}", user.Id, user.Username);
|
||
return Result.Success(message: "用户账户解锁成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "解锁用户账户失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "UNLOCK_USER_FAILED", "解锁用户账户失败。", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result UpdateLastLogin(Guid userId, string ipAddress, string userAgent)
|
||
{
|
||
try
|
||
{
|
||
var user = _users.FirstOrDefault(u => u.Id == userId);
|
||
if (user == null)
|
||
{
|
||
return Result.Fail("USER_NOT_FOUND", $"未找到ID为 {userId} 的用户。");
|
||
}
|
||
|
||
user.LastLoginAtUtc = DateTime.UtcNow;
|
||
user.LastLoginIp = ipAddress;
|
||
user.LastLoginIp = userAgent; // 这里应该是UserAgent,但为了简化使用同一个字段
|
||
|
||
_logger.LogInformation("更新用户最后登录信息成功: {UserId}", userId);
|
||
return Result.Success(message: "更新用户最后登录信息成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "更新用户最后登录信息失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "UPDATE_LAST_LOGIN_FAILED", "更新用户最后登录信息失败。", traceId);
|
||
return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public Result<UserStatistics> GetUserStatistics()
|
||
{
|
||
try
|
||
{
|
||
var now = DateTime.UtcNow;
|
||
var today = now.Date;
|
||
var thisWeekStart = today.AddDays(-(int)today.DayOfWeek);
|
||
var thisMonthStart = new DateTime(now.Year, now.Month, 1);
|
||
|
||
var stats = new UserStatistics
|
||
{
|
||
TotalUsers = _users.Count(u => u.Status != UserStatus.Deleted),
|
||
EnabledUsers = _users.Count(u => u.Status == UserStatus.Enabled),
|
||
DisabledUsers = _users.Count(u => u.Status == UserStatus.Disabled),
|
||
LockedUsers = _users.Count(u => u.Status == UserStatus.Locked),
|
||
TodayLoginUsers = _users.Count(u => u.LastLoginAtUtc.HasValue && u.LastLoginAtUtc.Value.Date == today),
|
||
ThisWeekLoginUsers = _users.Count(u => u.LastLoginAtUtc.HasValue && u.LastLoginAtUtc.Value >= thisWeekStart),
|
||
ThisMonthLoginUsers = _users.Count(u => u.LastLoginAtUtc.HasValue && u.LastLoginAtUtc.Value >= thisMonthStart)
|
||
};
|
||
|
||
return Result<UserStatistics>.Success(stats, message: "获取用户统计信息成功。");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
var traceId = Guid.NewGuid().ToString("N");
|
||
_logger.LogError(ex, "获取用户统计信息失败。TraceId: {TraceId}", traceId);
|
||
var result = Result.FromException(ex, "GET_USER_STATISTICS_FAILED", "获取用户统计信息失败。", traceId);
|
||
return Result<UserStatistics>.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray());
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成密码哈希。
|
||
/// </summary>
|
||
private static (string Hash, string Salt) GeneratePasswordHash(string password)
|
||
{
|
||
using var hmac = new HMACSHA256();
|
||
var salt = Convert.ToBase64String(hmac.Key);
|
||
var hash = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(password)));
|
||
return (hash, salt);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证密码哈希。
|
||
/// </summary>
|
||
private static bool VerifyPasswordHash(string password, string storedHash)
|
||
{
|
||
try
|
||
{
|
||
// 简化版本:直接比较明文(实际项目中应该使用安全的哈希算法)
|
||
// 这里为了演示,使用简单的哈希方式
|
||
var computedHash = ComputeSimpleHash(password);
|
||
return storedHash.Equals(computedHash, StringComparison.OrdinalIgnoreCase);
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算简单哈希(仅用于演示,生产环境应使用 BCrypt 等安全算法)。
|
||
/// </summary>
|
||
private static string ComputeSimpleHash(string input)
|
||
{
|
||
using var sha256 = SHA256.Create();
|
||
var bytes = Encoding.UTF8.GetBytes(input + "OrpaonVision2024"); // 加盐
|
||
var hash = sha256.ComputeHash(bytes);
|
||
return Convert.ToBase64String(hash);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 克隆用户信息,排除敏感数据。
|
||
/// </summary>
|
||
private static UserModel CloneUserWithoutSensitiveData(UserModel user)
|
||
{
|
||
return new UserModel
|
||
{
|
||
Id = user.Id,
|
||
Username = user.Username,
|
||
DisplayName = user.DisplayName,
|
||
Email = user.Email,
|
||
PhoneNumber = user.PhoneNumber,
|
||
Status = user.Status,
|
||
LastLoginAtUtc = user.LastLoginAtUtc,
|
||
LastLoginIp = user.LastLoginIp,
|
||
LoginFailedCount = user.LoginFailedCount,
|
||
LockedUntilUtc = user.LockedUntilUtc,
|
||
IsFirstLogin = user.IsFirstLogin,
|
||
CreatedAtUtc = user.CreatedAtUtc,
|
||
UpdatedAtUtc = user.UpdatedAtUtc,
|
||
CreatedBy = user.CreatedBy,
|
||
UpdatedBy = user.UpdatedBy,
|
||
Remark = user.Remark,
|
||
// 不包含密码相关字段
|
||
PasswordHash = string.Empty,
|
||
PasswordSalt = string.Empty
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化示例数据。
|
||
/// </summary>
|
||
private void InitializeSampleData()
|
||
{
|
||
var sampleUsers = new List<UserModel>
|
||
{
|
||
new UserModel
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Username = "admin",
|
||
DisplayName = "系统管理员",
|
||
Email = "admin@orpaon.com",
|
||
Status = UserStatus.Enabled,
|
||
PasswordHash = ComputeSimpleHash("admin"),
|
||
PasswordSalt = "OrpaonVision2024",
|
||
CreatedAtUtc = DateTime.UtcNow.AddDays(-30),
|
||
UpdatedAtUtc = DateTime.UtcNow.AddDays(-1),
|
||
CreatedBy = "System",
|
||
UpdatedBy = "System"
|
||
},
|
||
new UserModel
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Username = "operator1",
|
||
DisplayName = "操作员1",
|
||
Email = "operator1@orpaon.com",
|
||
Status = UserStatus.Enabled,
|
||
PasswordHash = ComputeSimpleHash("operator1"),
|
||
PasswordSalt = "OrpaonVision2024",
|
||
CreatedAtUtc = DateTime.UtcNow.AddDays(-20),
|
||
UpdatedAtUtc = DateTime.UtcNow.AddDays(-2),
|
||
CreatedBy = "admin",
|
||
UpdatedBy = "admin"
|
||
},
|
||
new UserModel
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Username = "engineer1",
|
||
DisplayName = "工艺工程师1",
|
||
Email = "engineer1@orpaon.com",
|
||
Status = UserStatus.Enabled,
|
||
PasswordHash = ComputeSimpleHash("engineer1"),
|
||
PasswordSalt = "OrpaonVision2024",
|
||
CreatedAtUtc = DateTime.UtcNow.AddDays(-15),
|
||
UpdatedAtUtc = DateTime.UtcNow.AddDays(-3),
|
||
CreatedBy = "admin",
|
||
UpdatedBy = "admin"
|
||
}
|
||
};
|
||
|
||
_users.AddRange(sampleUsers);
|
||
foreach (var user in sampleUsers)
|
||
{
|
||
var (hash, salt) = GeneratePasswordHash("123456"); // 默认密码
|
||
user.PasswordHash = hash;
|
||
user.PasswordSalt = salt;
|
||
}
|
||
|
||
_users.AddRange(sampleUsers);
|
||
_logger.LogInformation("已初始化 {Count} 个示例用户", sampleUsers.Count);
|
||
}
|
||
}
|