网站首页 网站源码
namespace Dpz.Core.Service.RepositoryServiceImpl;
/// <summary>
/// 用户安全服务实现
/// 提供用户SecurityStamp管理和安全相关功能
/// </summary>
public class UserSecurityService(
IRepository<User> userRepository,
ISecurityStampService securityStampService,
ILogger<UserSecurityService> logger
) : IUserSecurityService
{
/// <summary>
/// 更新用户的SecurityStamp
/// </summary>
public async Task<string> UpdateUserSecurityStampAsync(
string userId,
string reason = "Security update"
)
{
if (string.IsNullOrWhiteSpace(userId))
{
throw new ArgumentException("用户ID不能为空", nameof(userId));
}
try
{
// 生成新的SecurityStamp
var newSecurityStamp = securityStampService.GenerateSecurityStamp();
// 更新数据库
var update = Builders<User>
.Update.Set(x => x.Key, newSecurityStamp)
.Set(x => x.LastUpdateTime, DateTime.Now);
var result = await userRepository.UpdateAsync(x => x.Id == userId, update);
if (result.ModifiedCount > 0)
{
logger.LogInformation(
"用户 {UserId} 的SecurityStamp已更新,原因:{Reason},新SecurityStamp:{SecurityStamp}",
userId,
reason,
newSecurityStamp
);
return newSecurityStamp;
}
logger.LogWarning("用户 {UserId} 的SecurityStamp更新失败,用户可能不存在", userId);
throw new InvalidOperationException($"用户 {userId} 不存在或更新失败");
}
catch (Exception ex)
{
logger.LogError(
ex,
"更新用户 {UserId} 的SecurityStamp时发生错误,原因:{Reason}",
userId,
reason
);
throw;
}
}
/// <summary>
/// 验证用户的SecurityStamp是否有效(新方法,返回详细的验证结果)
/// </summary>
public async Task<UserSecurityValidationResult> ValidateUserSecurityStampDetailedAsync(
string userId,
string securityStamp
)
{
if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(securityStamp))
{
return UserSecurityValidationResult.SecurityStampInvalid;
}
try
{
// 首先验证SecurityStamp格式
if (!securityStampService.IsValidSecurityStamp(securityStamp))
{
return UserSecurityValidationResult.SecurityStampInvalid;
}
// 从数据库获取用户的当前SecurityStamp和启用状态
var user = await userRepository
.Collection.Find(x => x.Id == userId)
.Project(x => new { x.Key, x.Enable })
.FirstOrDefaultAsync();
if (user == null)
{
return UserSecurityValidationResult.UserNotFound;
}
if (user.Enable == false)
{
return UserSecurityValidationResult.UserDisabled;
}
if (user.Key != securityStamp)
{
return UserSecurityValidationResult.SecurityStampInvalid;
}
return UserSecurityValidationResult.Valid;
}
catch (Exception ex)
{
logger.LogError(ex, "验证用户 {UserId} 的SecurityStamp时发生错误", userId);
return UserSecurityValidationResult.SecurityStampInvalid;
}
}
/// <summary>
/// 验证用户的SecurityStamp是否有效
/// </summary>
public async Task<bool> ValidateUserSecurityStampAsync(string userId, string securityStamp)
{
if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(securityStamp))
{
return false;
}
try
{
// 首先验证SecurityStamp格式
if (!securityStampService.IsValidSecurityStamp(securityStamp))
{
return false;
}
// 从数据库获取用户的当前SecurityStamp
var user = await userRepository
.Collection.Find(x => x.Id == userId)
.Project(x => new { x.Key, x.Enable })
.FirstOrDefaultAsync();
return user != null && user.Enable != false && user.Key == securityStamp;
}
catch (Exception ex)
{
logger.LogError(ex, "验证用户 {UserId} 的SecurityStamp时发生错误", userId);
return false;
}
}
/// <summary>
/// 强制用户重新登录
/// </summary>
public async Task<bool> ForceUserReauthenticationAsync(
string userId,
string reason = "Security enforcement"
)
{
try
{
await UpdateUserSecurityStampAsync(userId, $"强制重新认证:{reason}");
logger.LogInformation(
"用户 {UserId} 被强制要求重新登录,原因:{Reason}",
userId,
reason
);
return true;
}
catch (Exception ex)
{
logger.LogError(
ex,
"强制用户 {UserId} 重新登录时发生错误,原因:{Reason}",
userId,
reason
);
return false;
}
}
/// <summary>
/// 批量更新多个用户的SecurityStamp
/// </summary>
public async Task<int> BatchUpdateSecurityStampsAsync(
List<string> userIds,
string reason = "Batch security update"
)
{
if (userIds.Count == 0)
{
return 0;
}
var userIdList = userIds.ToList();
var successCount = 0;
logger.LogInformation(
"开始批量更新 {Count} 个用户的SecurityStamp,原因:{Reason}",
userIdList.Count,
reason
);
foreach (var userId in userIdList)
{
try
{
await UpdateUserSecurityStampAsync(userId, reason);
successCount++;
}
catch (Exception ex)
{
logger.LogError(ex, "批量更新用户 {UserId} 的SecurityStamp失败", userId);
// 继续处理其他用户,不中断批量操作
}
}
logger.LogInformation(
"批量更新SecurityStamp完成,成功:{SuccessCount}/{TotalCount},原因:{Reason}",
successCount,
userIdList.Count,
reason
);
return successCount;
}
/// <summary>
/// 在密码修改时更新用户的SecurityStamp
/// </summary>
public async Task<string> UpdateSecurityStampOnPasswordChangeAsync(string userId)
{
return await UpdateUserSecurityStampAsync(userId, "密码修改");
}
}
/// <summary>
/// 用户安全服务的扩展方法
/// </summary>
public static class UserSecurityServiceExtensions
{
/// <summary>
/// 在密码修改时更新SecurityStamp
/// </summary>
public static async Task<string> UpdateSecurityStampOnPasswordChangeAsync(
this IUserSecurityService service,
string userId
)
{
return await service.UpdateUserSecurityStampAsync(userId, "密码修改");
}
/// <summary>
/// 在账户被锁定时更新SecurityStamp
/// </summary>
public static async Task<bool> UpdateSecurityStampOnAccountLockAsync(
this IUserSecurityService service,
string userId
)
{
return await service.ForceUserReauthenticationAsync(userId, "账户被锁定");
}
/// <summary>
/// 在权限变更时更新SecurityStamp
/// </summary>
public static async Task<bool> UpdateSecurityStampOnPermissionChangeAsync(
this IUserSecurityService service,
string userId
)
{
return await service.ForceUserReauthenticationAsync(userId, "权限变更");
}
}
上述代码实现了一个用户安全服务 (UserSecurityService),主要用于管理用户的安全标识(SecurityStamp)以及与安全相关的功能。以下是代码的主要功能和结构的详细解释:
UserSecurityService: 这是一个实现了 IUserSecurityService 接口的类,负责用户安全相关的操作。IRepository<User> userRepository: 用于与用户数据进行交互的仓储接口。ISecurityStampService securityStampService: 用于生成和验证安全标识的服务。ILogger<UserSecurityService> logger: 用于记录日志的接口。UpdateUserSecurityStampAsyncuserId: 用户的唯一标识。reason: 更新的原因,默认为 "Security update"。userId 是否为空。ValidateUserSecurityStampAsyncuserId: 用户的唯一标识。securityStamp: 要验证的安全标识。ForceUserReauthenticationAsyncuserId: 用户的唯一标识。reason: 强制重新认证的原因,默认为 "Security enforcement"。UpdateUserSecurityStampAsync 方法更新安全标识。BatchUpdateSecurityStampsAsyncuserIds: 用户ID的列表。reason: 批量更新的原因,默认为 "Batch security update"。UpdateSecurityStampOnPasswordChangeAsyncuserId: 用户的唯一标识。UpdateUserSecurityStampAsync 方法,原因设置为 "密码修改"。UserSecurityServiceExtensions: 提供了一些扩展方法,方便在特定情况下更新安全标识。UpdateSecurityStampOnPasswordChangeAsync: 在密码修改时更新安全标识。UpdateSecurityStampOnAccountLockAsync: 在账户被锁定时强制用户重新认证。UpdateSecurityStampOnPermissionChangeAsync: 在权限变更时强制用户重新认证。整体而言,这段代码提供了一套完整的用户安全管理功能,主要用于更新和验证用户的安全标识,确保用户的安全性。通过日志记录,开发人员可以追踪安全相关的操作和事件。
