233 lines
6.7 KiB
C#
233 lines
6.7 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using LingAdmin.IdentityService.Services;
|
|
using LingAdmin.Shared.DTOs;
|
|
using System.Security.Claims;
|
|
|
|
namespace LingAdmin.IdentityService.Controllers;
|
|
|
|
/// <summary>
|
|
/// 认证控制器 - 处理用户注册、登录、令牌刷新等
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class AuthController : ControllerBase
|
|
{
|
|
private readonly IAuthService _authService;
|
|
private readonly ILogger<AuthController> _logger;
|
|
|
|
public AuthController(IAuthService authService, ILogger<AuthController> logger)
|
|
{
|
|
_authService = authService;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用户注册
|
|
/// </summary>
|
|
[HttpPost("register")]
|
|
public async Task<ActionResult<ApiResponse<UserDto>>> Register([FromBody] RegisterRequest request)
|
|
{
|
|
var (user, error) = await _authService.RegisterAsync(request);
|
|
|
|
if (error != null)
|
|
{
|
|
return BadRequest(ApiResponse<UserDto>.Error(error));
|
|
}
|
|
|
|
var userDto = new UserDto
|
|
{
|
|
Id = user!.Id,
|
|
Name = user.Name,
|
|
Email = user.Email,
|
|
Status = user.Status,
|
|
CreatedAt = user.CreatedAt
|
|
};
|
|
|
|
return CreatedAtAction(nameof(GetProfile), null, ApiResponse<UserDto>.Created(userDto, "Registration successful"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用户登录
|
|
/// </summary>
|
|
[HttpPost("login")]
|
|
public async Task<ActionResult<ApiResponse<LoginResponse>>> Login([FromBody] LoginRequest request)
|
|
{
|
|
var ipAddress = GetIpAddress();
|
|
var (response, error) = await _authService.LoginAsync(request, ipAddress);
|
|
|
|
if (error != null)
|
|
{
|
|
return Unauthorized(ApiResponse<LoginResponse>.Unauthorized(error));
|
|
}
|
|
|
|
SetRefreshTokenCookie(response!.RefreshToken);
|
|
return Ok(ApiResponse<LoginResponse>.Ok(response, "Login successful"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 刷新访问令牌
|
|
/// </summary>
|
|
[HttpPost("refresh-token")]
|
|
public async Task<ActionResult<ApiResponse<TokenRefreshResponse>>> RefreshToken([FromBody] RefreshTokenRequest? request = null)
|
|
{
|
|
var refreshToken = request?.RefreshToken ?? Request.Cookies["refreshToken"];
|
|
|
|
if (string.IsNullOrEmpty(refreshToken))
|
|
{
|
|
return BadRequest(ApiResponse<TokenRefreshResponse>.Error("Refresh token is required"));
|
|
}
|
|
|
|
var ipAddress = GetIpAddress();
|
|
var (response, error) = await _authService.RefreshTokenAsync(refreshToken, ipAddress);
|
|
|
|
if (error != null)
|
|
{
|
|
return Unauthorized(ApiResponse<TokenRefreshResponse>.Unauthorized(error));
|
|
}
|
|
|
|
SetRefreshTokenCookie(response!.RefreshToken);
|
|
return Ok(ApiResponse<TokenRefreshResponse>.Ok(response));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 登出(撤销刷新令牌)
|
|
/// </summary>
|
|
[HttpPost("logout")]
|
|
public async Task<ActionResult<ApiResponse<object>>> Logout([FromBody] RefreshTokenRequest? request = null)
|
|
{
|
|
var refreshToken = request?.RefreshToken ?? Request.Cookies["refreshToken"];
|
|
|
|
if (string.IsNullOrEmpty(refreshToken))
|
|
{
|
|
return BadRequest(ApiResponse<object>.Error("Refresh token is required"));
|
|
}
|
|
|
|
var ipAddress = GetIpAddress();
|
|
var result = await _authService.RevokeTokenAsync(refreshToken, ipAddress);
|
|
|
|
if (!result)
|
|
{
|
|
return NotFound(ApiResponse<object>.NotFound("Token not found or already revoked"));
|
|
}
|
|
|
|
// Clear the refresh token cookie
|
|
Response.Cookies.Delete("refreshToken");
|
|
|
|
return Ok(ApiResponse<object>.Ok(new { }, "Logout successful"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 修改密码
|
|
/// </summary>
|
|
[Authorize]
|
|
[HttpPost("change-password")]
|
|
public async Task<ActionResult<ApiResponse<object>>> ChangePassword([FromBody] ChangePasswordRequest request)
|
|
{
|
|
var userId = GetCurrentUserId();
|
|
if (userId == null)
|
|
{
|
|
return Unauthorized(ApiResponse<object>.Unauthorized());
|
|
}
|
|
|
|
var (success, error) = await _authService.ChangePasswordAsync(userId.Value, request);
|
|
|
|
if (!success)
|
|
{
|
|
return BadRequest(ApiResponse<object>.Error(error!));
|
|
}
|
|
|
|
// Clear refresh token cookie after password change
|
|
Response.Cookies.Delete("refreshToken");
|
|
|
|
return Ok(ApiResponse<object>.Ok(new { }, "Password changed successfully"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前用户信息
|
|
/// </summary>
|
|
[Authorize]
|
|
[HttpGet("profile")]
|
|
public async Task<ActionResult<ApiResponse<UserDto>>> GetProfile()
|
|
{
|
|
var userId = GetCurrentUserId();
|
|
if (userId == null)
|
|
{
|
|
return Unauthorized(ApiResponse<UserDto>.Unauthorized());
|
|
}
|
|
|
|
var user = await _authService.GetUserByIdAsync(userId.Value);
|
|
if (user == null)
|
|
{
|
|
return NotFound(ApiResponse<UserDto>.NotFound("User not found"));
|
|
}
|
|
|
|
var userDto = new UserDto
|
|
{
|
|
Id = user.Id,
|
|
Name = user.Name,
|
|
Email = user.Email,
|
|
Status = user.Status,
|
|
CreatedAt = user.CreatedAt,
|
|
LastLoginAt = user.LastLoginAt
|
|
};
|
|
|
|
return Ok(ApiResponse<UserDto>.Ok(userDto));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 验证令牌是否有效
|
|
/// </summary>
|
|
[Authorize]
|
|
[HttpGet("validate")]
|
|
public ActionResult<ApiResponse<object>> ValidateToken()
|
|
{
|
|
var userId = GetCurrentUserId();
|
|
var email = User.FindFirst(ClaimTypes.Email)?.Value;
|
|
var roles = User.FindAll(ClaimTypes.Role).Select(c => c.Value).ToList();
|
|
|
|
return Ok(ApiResponse<object>.Ok(new
|
|
{
|
|
UserId = userId,
|
|
Email = email,
|
|
Roles = roles,
|
|
IsValid = true
|
|
}));
|
|
}
|
|
|
|
#region Private Helpers
|
|
|
|
private int? GetCurrentUserId()
|
|
{
|
|
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (int.TryParse(userIdClaim, out var userId))
|
|
{
|
|
return userId;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private string? GetIpAddress()
|
|
{
|
|
if (Request.Headers.ContainsKey("X-Forwarded-For"))
|
|
{
|
|
return Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
|
}
|
|
return HttpContext.Connection.RemoteIpAddress?.MapToIPv4().ToString();
|
|
}
|
|
|
|
private void SetRefreshTokenCookie(string token)
|
|
{
|
|
var cookieOptions = new CookieOptions
|
|
{
|
|
HttpOnly = true,
|
|
Expires = DateTime.UtcNow.AddDays(7),
|
|
SameSite = SameSiteMode.Strict,
|
|
Secure = true
|
|
};
|
|
Response.Cookies.Append("refreshToken", token, cookieOptions);
|
|
}
|
|
|
|
#endregion
|
|
}
|