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