12 changed files with 381 additions and 34 deletions
@ -0,0 +1,17 @@ |
|||||
|
using MediatR; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using CellularManagement.Application.Features.Auth.Commands.AuthenticateUser; |
||||
|
|
||||
|
namespace CellularManagement.Application.Features.Auth.Commands.RefreshToken; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 刷新令牌命令
|
||||
|
/// </summary>
|
||||
|
public class RefreshTokenCommand : IRequest<OperationResult<AuthenticateUserResponse>> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 刷新令牌
|
||||
|
/// </summary>
|
||||
|
[Required(ErrorMessage = "刷新令牌不能为空")] |
||||
|
public string RefreshToken { get; set; } = string.Empty; |
||||
|
} |
||||
@ -0,0 +1,122 @@ |
|||||
|
using MediatR; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using CellularManagement.Application.Common; |
||||
|
using CellularManagement.Application.Services; |
||||
|
using System.Security.Claims; |
||||
|
using CellularManagement.Application.Features.Auth.Commands.AuthenticateUser; |
||||
|
using CellularManagement.Application.Features.Auth.Common; |
||||
|
using CellularManagement.Domain.Repositories; |
||||
|
|
||||
|
namespace CellularManagement.Application.Features.Auth.Commands.RefreshToken; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 刷新令牌命令处理器
|
||||
|
/// </summary>
|
||||
|
public class RefreshTokenCommandHandler : IRequestHandler<RefreshTokenCommand, OperationResult<AuthenticateUserResponse>> |
||||
|
{ |
||||
|
private readonly IJwtProvider _jwtProvider; |
||||
|
private readonly ILogger<RefreshTokenCommandHandler> _logger; |
||||
|
private readonly IUserRoleRepository _userRoleRepository; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 构造函数
|
||||
|
/// </summary>
|
||||
|
/// <param name="jwtProvider">JWT提供者</param>
|
||||
|
/// <param name="logger">日志记录器</param>
|
||||
|
/// <param name="userRoleRepository">用户角色仓储</param>
|
||||
|
public RefreshTokenCommandHandler( |
||||
|
IJwtProvider jwtProvider, |
||||
|
ILogger<RefreshTokenCommandHandler> logger, |
||||
|
IUserRoleRepository userRoleRepository) |
||||
|
{ |
||||
|
_jwtProvider = jwtProvider; |
||||
|
_logger = logger; |
||||
|
_userRoleRepository = userRoleRepository; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 处理刷新令牌请求
|
||||
|
/// </summary>
|
||||
|
/// <param name="request">刷新令牌命令</param>
|
||||
|
/// <param name="cancellationToken">取消令牌</param>
|
||||
|
/// <returns>刷新令牌结果</returns>
|
||||
|
public async Task<OperationResult<AuthenticateUserResponse>> Handle( |
||||
|
RefreshTokenCommand request, |
||||
|
CancellationToken cancellationToken) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
_logger.LogInformation("开始处理刷新令牌请求"); |
||||
|
|
||||
|
// 验证刷新令牌
|
||||
|
if (!_jwtProvider.ValidateToken(request.RefreshToken)) |
||||
|
{ |
||||
|
_logger.LogWarning("刷新令牌验证失败"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateFailure("无效的刷新令牌"); |
||||
|
} |
||||
|
|
||||
|
// 获取令牌中的声明
|
||||
|
var claims = _jwtProvider.GetClaimsFromToken(request.RefreshToken); |
||||
|
if (!claims.Any()) |
||||
|
{ |
||||
|
_logger.LogWarning("刷新令牌中未找到声明"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateFailure("无效的刷新令牌"); |
||||
|
} |
||||
|
|
||||
|
// 检查令牌类型
|
||||
|
var tokenType = _jwtProvider.GetTokenType(request.RefreshToken); |
||||
|
if (tokenType != "refresh_token") |
||||
|
{ |
||||
|
_logger.LogWarning("令牌类型不是刷新令牌"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateFailure("无效的刷新令牌"); |
||||
|
} |
||||
|
|
||||
|
// 检查令牌是否在黑名单中
|
||||
|
if (_jwtProvider.GetAllClaims(request.RefreshToken).ContainsKey("blacklisted")) |
||||
|
{ |
||||
|
_logger.LogWarning("刷新令牌已被列入黑名单"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateFailure("刷新令牌已被撤销"); |
||||
|
} |
||||
|
|
||||
|
// 获取用户ID
|
||||
|
var userId = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value; |
||||
|
if (string.IsNullOrEmpty(userId)) |
||||
|
{ |
||||
|
_logger.LogWarning("刷新令牌中未找到用户ID"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateFailure("无效的刷新令牌"); |
||||
|
} |
||||
|
|
||||
|
// 获取用户角色
|
||||
|
var roles = await _userRoleRepository.GetUserRolesAsync(userId, cancellationToken); |
||||
|
|
||||
|
// 生成新的访问令牌
|
||||
|
var accessToken = _jwtProvider.GenerateAccessToken(claims); |
||||
|
|
||||
|
// 生成新的刷新令牌
|
||||
|
var refreshToken = _jwtProvider.GenerateRefreshToken(claims); |
||||
|
|
||||
|
// 撤销旧的刷新令牌
|
||||
|
_jwtProvider.RevokeToken(request.RefreshToken); |
||||
|
|
||||
|
// 获取令牌过期时间
|
||||
|
var expiresAt = _jwtProvider.GetTokenExpiration(accessToken); |
||||
|
var permissions = new Dictionary<string, bool>(); |
||||
|
// 创建用户信息
|
||||
|
var userInfo = new UserInfo( |
||||
|
userId, |
||||
|
claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value ?? string.Empty, |
||||
|
claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value ?? string.Empty, |
||||
|
claims.FirstOrDefault(c => c.Type == ClaimTypes.MobilePhone)?.Value, |
||||
|
roles, permissions); |
||||
|
|
||||
|
_logger.LogInformation("刷新令牌成功"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateSuccess( |
||||
|
new AuthenticateUserResponse(accessToken, refreshToken, expiresAt, userInfo)); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_logger.LogError(ex, "刷新令牌时发生异常"); |
||||
|
return OperationResult<AuthenticateUserResponse>.CreateFailure("刷新令牌失败,请稍后重试"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
namespace CellularManagement.Application.Features.Auth.Commands.RefreshToken; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 刷新令牌响应
|
||||
|
/// </summary>
|
||||
|
public class RefreshTokenResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 访问令牌
|
||||
|
/// </summary>
|
||||
|
public string AccessToken { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 刷新令牌
|
||||
|
/// </summary>
|
||||
|
public string RefreshToken { get; set; } = string.Empty; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 过期时间(分钟)
|
||||
|
/// </summary>
|
||||
|
public int ExpiresIn { get; set; } |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using MediatR; |
||||
|
using CellularManagement.Application.Common; |
||||
|
|
||||
|
namespace CellularManagement.Application.Features.Roles.Queries; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取所有角色的查询
|
||||
|
/// </summary>
|
||||
|
public record GetAllRolesQuery : IRequest<OperationResult<GetAllRolesResponse>>; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 获取所有角色的响应
|
||||
|
/// </summary>
|
||||
|
public record GetAllRolesResponse(IEnumerable<RoleDto> Roles); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 角色数据传输对象
|
||||
|
/// </summary>
|
||||
|
public record RoleDto(string Id, string Name, string Description); |
||||
@ -0,0 +1,87 @@ |
|||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using MediatR; |
||||
|
using CellularManagement.Domain.Entities; |
||||
|
using CellularManagement.Application.Features.Roles.Queries.GetRole; |
||||
|
using CellularManagement.Application.Features.Roles.Queries; |
||||
|
|
||||
|
namespace CellularManagement.Application.Features.Roles.Queries; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 角色查询处理器
|
||||
|
/// </summary>
|
||||
|
public sealed class RoleQueryHandler : |
||||
|
IRequestHandler<GetRoleQuery, OperationResult<GetRoleResponse>>, |
||||
|
IRequestHandler<GetAllRolesQuery, OperationResult<GetAllRolesResponse>> |
||||
|
{ |
||||
|
private readonly RoleManager<AppRole> _roleManager; |
||||
|
private readonly ILogger<RoleQueryHandler> _logger; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 初始化处理器
|
||||
|
/// </summary>
|
||||
|
public RoleQueryHandler( |
||||
|
RoleManager<AppRole> roleManager, |
||||
|
ILogger<RoleQueryHandler> logger) |
||||
|
{ |
||||
|
_roleManager = roleManager; |
||||
|
_logger = logger; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 处理获取角色请求
|
||||
|
/// </summary>
|
||||
|
public async Task<OperationResult<GetRoleResponse>> Handle( |
||||
|
GetRoleQuery request, |
||||
|
CancellationToken cancellationToken) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// 查找角色
|
||||
|
var role = await _roleManager.FindByIdAsync(request.RoleId); |
||||
|
if (role == null) |
||||
|
{ |
||||
|
_logger.LogWarning("角色 {RoleId} 不存在", request.RoleId); |
||||
|
return OperationResult<GetRoleResponse>.CreateFailure("角色不存在"); |
||||
|
} |
||||
|
|
||||
|
_logger.LogInformation("获取角色 {RoleId} 成功", request.RoleId); |
||||
|
|
||||
|
return OperationResult<GetRoleResponse>.CreateSuccess( |
||||
|
new GetRoleResponse(role.Id, role.Name, role.Description)); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_logger.LogError(ex, "获取角色 {RoleId} 失败", request.RoleId); |
||||
|
return OperationResult<GetRoleResponse>.CreateFailure("获取角色失败,请稍后重试"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 处理获取所有角色请求
|
||||
|
/// </summary>
|
||||
|
public async Task<OperationResult<GetAllRolesResponse>> Handle( |
||||
|
GetAllRolesQuery request, |
||||
|
CancellationToken cancellationToken) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var roles = _roleManager.Roles.ToList(); |
||||
|
var roleDtos = roles.Select(role => new RoleDto( |
||||
|
role.Id, |
||||
|
role.Name, |
||||
|
role.Description |
||||
|
)); |
||||
|
|
||||
|
_logger.LogInformation("成功获取所有角色,共 {Count} 个", roles.Count); |
||||
|
|
||||
|
return OperationResult<GetAllRolesResponse>.CreateSuccess( |
||||
|
new GetAllRolesResponse(roleDtos)); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_logger.LogError(ex, "获取所有角色失败"); |
||||
|
return OperationResult<GetAllRolesResponse>.CreateFailure("获取角色列表失败,请稍后重试"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue