using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using LingAdmin.IdentityService.Services; using LingAdmin.Shared.DTOs; using System.Security.Claims; namespace LingAdmin.IdentityService.Controllers; /// /// 认证控制器 - 处理用户注册、登录、令牌刷新等 /// [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly IAuthService _authService; private readonly ILogger _logger; public AuthController(IAuthService authService, ILogger logger) { _authService = authService; _logger = logger; } /// /// 用户注册 /// [HttpPost("register")] public async Task>> Register([FromBody] RegisterRequest request) { var (user, error) = await _authService.RegisterAsync(request); if (error != null) { return BadRequest(ApiResponse.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.Created(userDto, "Registration successful")); } /// /// 用户登录 /// [HttpPost("login")] public async Task>> Login([FromBody] LoginRequest request) { var ipAddress = GetIpAddress(); var (response, error) = await _authService.LoginAsync(request, ipAddress); if (error != null) { return Unauthorized(ApiResponse.Unauthorized(error)); } SetRefreshTokenCookie(response!.RefreshToken); return Ok(ApiResponse.Ok(response, "Login successful")); } /// /// 刷新访问令牌 /// [HttpPost("refresh-token")] public async Task>> RefreshToken([FromBody] RefreshTokenRequest? request = null) { var refreshToken = request?.RefreshToken ?? Request.Cookies["refreshToken"]; if (string.IsNullOrEmpty(refreshToken)) { return BadRequest(ApiResponse.Error("Refresh token is required")); } var ipAddress = GetIpAddress(); var (response, error) = await _authService.RefreshTokenAsync(refreshToken, ipAddress); if (error != null) { return Unauthorized(ApiResponse.Unauthorized(error)); } SetRefreshTokenCookie(response!.RefreshToken); return Ok(ApiResponse.Ok(response)); } /// /// 登出(撤销刷新令牌) /// [HttpPost("logout")] public async Task>> Logout([FromBody] RefreshTokenRequest? request = null) { var refreshToken = request?.RefreshToken ?? Request.Cookies["refreshToken"]; if (string.IsNullOrEmpty(refreshToken)) { return BadRequest(ApiResponse.Error("Refresh token is required")); } var ipAddress = GetIpAddress(); var result = await _authService.RevokeTokenAsync(refreshToken, ipAddress); if (!result) { return NotFound(ApiResponse.NotFound("Token not found or already revoked")); } // Clear the refresh token cookie Response.Cookies.Delete("refreshToken"); return Ok(ApiResponse.Ok(new { }, "Logout successful")); } /// /// 修改密码 /// [Authorize] [HttpPost("change-password")] public async Task>> ChangePassword([FromBody] ChangePasswordRequest request) { var userId = GetCurrentUserId(); if (userId == null) { return Unauthorized(ApiResponse.Unauthorized()); } var (success, error) = await _authService.ChangePasswordAsync(userId.Value, request); if (!success) { return BadRequest(ApiResponse.Error(error!)); } // Clear refresh token cookie after password change Response.Cookies.Delete("refreshToken"); return Ok(ApiResponse.Ok(new { }, "Password changed successfully")); } /// /// 获取当前用户信息 /// [Authorize] [HttpGet("profile")] public async Task>> GetProfile() { var userId = GetCurrentUserId(); if (userId == null) { return Unauthorized(ApiResponse.Unauthorized()); } var user = await _authService.GetUserByIdAsync(userId.Value); if (user == null) { return NotFound(ApiResponse.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.Ok(userDto)); } /// /// 验证令牌是否有效 /// [Authorize] [HttpGet("validate")] public ActionResult> 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.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 }