You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
8.4 KiB
224 lines
8.4 KiB
using Microsoft.AspNetCore.Mvc;
|
|
using MediatR;
|
|
using CellularManagement.Application.Features.Auth.Commands.AuthenticateUser;
|
|
using CellularManagement.Application.Features.Auth.Commands.RegisterUser;
|
|
using CellularManagement.Application.Features.Auth.Commands.RefreshToken;
|
|
using CellularManagement.Application.Common;
|
|
using Microsoft.Extensions.Logging;
|
|
using CellularManagement.Domain.Services;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using CellularManagement.Infrastructure.Configurations;
|
|
using Microsoft.Extensions.Options;
|
|
using Microsoft.AspNetCore.Http;
|
|
using CellularManagement.Presentation.Abstractions;
|
|
using CellularManagement.Application.Features.Auth.Commands.Login;
|
|
using Swashbuckle.AspNetCore.Filters;
|
|
using CellularManagement.Domain.Common;
|
|
|
|
namespace CellularManagement.Presentation.Controllers;
|
|
|
|
/// <summary>
|
|
/// 认证控制器
|
|
/// 提供用户认证相关的 API 接口,包括登录和注册功能
|
|
/// </summary>
|
|
public class AuthController : ApiController
|
|
{
|
|
private readonly ILogger<AuthController> _logger;
|
|
private readonly ICacheService _cache;
|
|
private readonly AuthConfiguration _authConfig;
|
|
|
|
/// <summary>
|
|
/// 初始化认证控制器
|
|
/// </summary>
|
|
/// <param name="mediator">MediatR 中介者,用于处理命令和查询</param>
|
|
/// <param name="logger">日志记录器</param>
|
|
/// <param name="cache">缓存服务</param>
|
|
/// <param name="authConfig">认证配置</param>
|
|
public AuthController(
|
|
IMediator mediator,
|
|
ILogger<AuthController> logger,
|
|
ICacheService cache,
|
|
IOptions<AuthConfiguration> authConfig) : base(mediator)
|
|
{
|
|
_logger = logger;
|
|
_cache = cache;
|
|
_authConfig = authConfig.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用户登录
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 示例请求:
|
|
///
|
|
/// POST /api/auth/login
|
|
/// {
|
|
/// "userNameOrEmail": "用户名或邮箱",
|
|
/// "password": "密码"
|
|
/// }
|
|
///
|
|
/// </remarks>
|
|
/// <param name="command">登录命令,包含用户名/邮箱和密码</param>
|
|
/// <returns>
|
|
/// 登录结果,包含:
|
|
/// - 成功:返回用户信息和访问令牌
|
|
/// - 失败:返回错误信息
|
|
/// </returns>
|
|
/// <response code="200">登录成功,返回用户信息和令牌</response>
|
|
/// <response code="400">登录失败,返回错误信息</response>
|
|
/// <response code="429">登录尝试次数过多</response>
|
|
[HttpPost()]
|
|
[SwaggerRequestExample(typeof(LoginRequest), typeof(LoginRequestExample))]
|
|
[ProducesResponseType(typeof(OperationResult<AuthenticateUserResponse>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(OperationResult<AuthenticateUserResponse>), StatusCodes.Status400BadRequest)]
|
|
[ProducesResponseType(typeof(OperationResult<AuthenticateUserResponse>), StatusCodes.Status429TooManyRequests)]
|
|
public async Task<ActionResult<OperationResult<AuthenticateUserResponse>>> Login([FromBody] AuthenticateUserCommand command)
|
|
{
|
|
try
|
|
{
|
|
// 检查登录尝试次数
|
|
var cacheKey = string.Format(_authConfig.LoginAttemptsCacheKeyFormat, command.UserName);
|
|
var attempts = _cache.Get<int>(cacheKey);
|
|
|
|
if (attempts >= _authConfig.MaxLoginAttempts)
|
|
{
|
|
_logger.LogWarning("用户 {UserName} 登录尝试次数过多", command.UserName);
|
|
return StatusCode(StatusCodes.Status429TooManyRequests,
|
|
OperationResult<AuthenticateUserResponse>.CreateFailure("登录尝试次数过多,请稍后再试"));
|
|
}
|
|
|
|
// 执行登录
|
|
var result = await mediator.Send(command);
|
|
|
|
if (!result.IsSuccess)
|
|
{
|
|
// 增加登录尝试次数
|
|
var options = new MemoryCacheEntryOptions()
|
|
.SetAbsoluteExpiration(TimeSpan.FromMinutes(_authConfig.LoginAttemptsWindowMinutes));
|
|
_cache.Set(cacheKey, attempts + 1, options);
|
|
|
|
_logger.LogWarning("用户 {UserName} 登录失败: {Error}",
|
|
command.UserName,
|
|
result.ErrorMessages?.FirstOrDefault());
|
|
}
|
|
else
|
|
{
|
|
// 清除登录尝试次数
|
|
_cache.Remove(cacheKey);
|
|
_logger.LogInformation("用户 {UserName} 登录成功", command.UserName);
|
|
}
|
|
_logger.LogWarning($"Bearer {result.Data.AccessToken}");
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "用户 {UserName} 登录时发生异常", command.UserName);
|
|
return StatusCode(StatusCodes.Status500InternalServerError,
|
|
OperationResult<AuthenticateUserResponse>.CreateFailure("系统错误,请稍后重试"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用户注册
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 示例请求:
|
|
///
|
|
/// POST /api/auth/register
|
|
/// {
|
|
/// "userName": "用户名",
|
|
/// "email": "邮箱",
|
|
/// "password": "密码",
|
|
/// "confirmPassword": "确认密码",
|
|
/// "phoneNumber": "手机号"
|
|
/// }
|
|
///
|
|
/// </remarks>
|
|
/// <param name="command">注册命令,包含用户注册信息</param>
|
|
/// <returns>
|
|
/// 注册结果,包含:
|
|
/// - 成功:返回用户ID
|
|
/// - 失败:返回错误信息
|
|
/// </returns>
|
|
/// <response code="200">注册成功,返回用户ID</response>
|
|
/// <response code="400">注册失败,返回错误信息</response>
|
|
[HttpPost()]
|
|
[ProducesResponseType(typeof(OperationResult<RegisterUserResponse>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(OperationResult<RegisterUserResponse>), StatusCodes.Status400BadRequest)]
|
|
public async Task<ActionResult<OperationResult<RegisterUserResponse>>> Register([FromBody] RegisterUserCommand command)
|
|
{
|
|
try
|
|
{
|
|
// 执行注册
|
|
var result = await mediator.Send(command);
|
|
|
|
if (result.IsSuccess)
|
|
{
|
|
_logger.LogInformation("用户 {UserName} 注册成功", command.UserName);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("用户 {UserName} 注册失败: {Error}",
|
|
command.UserName,
|
|
result.ErrorMessages?.FirstOrDefault());
|
|
}
|
|
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "用户 {UserName} 注册时发生异常", command.UserName);
|
|
return StatusCode(StatusCodes.Status500InternalServerError,
|
|
OperationResult<RegisterUserResponse>.CreateFailure("系统错误,请稍后重试"));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 刷新令牌
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 示例请求:
|
|
///
|
|
/// POST /api/auth/refresh-token
|
|
/// {
|
|
/// "refreshToken": "刷新令牌"
|
|
/// }
|
|
///
|
|
/// </remarks>
|
|
/// <param name="command">刷新令牌命令</param>
|
|
/// <returns>
|
|
/// 刷新结果,包含:
|
|
/// - 成功:返回用户信息和新的访问令牌
|
|
/// - 失败:返回错误信息
|
|
/// </returns>
|
|
/// <response code="200">刷新成功,返回用户信息和新的令牌</response>
|
|
/// <response code="400">刷新失败,返回错误信息</response>
|
|
[HttpPost()]
|
|
[ProducesResponseType(typeof(OperationResult<AuthenticateUserResponse>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(OperationResult<AuthenticateUserResponse>), StatusCodes.Status400BadRequest)]
|
|
public async Task<ActionResult<OperationResult<AuthenticateUserResponse>>> RefreshToken([FromBody] RefreshTokenCommand command)
|
|
{
|
|
try
|
|
{
|
|
var result = await mediator.Send(command);
|
|
|
|
if (result.IsSuccess)
|
|
{
|
|
_logger.LogInformation("令牌刷新成功");
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("令牌刷新失败: {Error}",
|
|
result.ErrorMessages?.FirstOrDefault());
|
|
}
|
|
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "刷新令牌时发生异常");
|
|
return StatusCode(StatusCodes.Status500InternalServerError,
|
|
OperationResult<AuthenticateUserResponse>.CreateFailure("系统错误,请稍后重试"));
|
|
}
|
|
}
|
|
}
|