SPMS_API/SPMS.API/Controllers/AuthController.cs
SEAN 5d49a2ce49 feat: 이메일 중복 체크 API 구현 (#58)
POST /v1/in/auth/email/check 엔드포인트 추가.
기존 EmailExistsAsync 활용하여 이메일 사용 가능 여부 반환.
2026-02-10 10:23:25 +09:00

114 lines
4.6 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using SPMS.Application.DTOs.Auth;
using SPMS.Application.Interfaces;
using SPMS.Domain.Common;
namespace SPMS.API.Controllers;
[ApiController]
[Route("v1/in/auth")]
[ApiExplorerSettings(GroupName = "auth")]
public class AuthController : ControllerBase
{
private readonly IAuthService _authService;
public AuthController(IAuthService authService)
{
_authService = authService;
}
[HttpPost("signup")]
[AllowAnonymous]
[SwaggerOperation(
Summary = "회원가입",
Description = "새로운 관리자 계정을 생성합니다. 이메일 인증이 필요합니다.")]
[SwaggerResponse(200, "회원가입 성공", typeof(ApiResponse<SignupResponseDto>))]
[SwaggerResponse(400, "잘못된 요청")]
[SwaggerResponse(409, "이미 사용 중인 이메일")]
public async Task<IActionResult> SignupAsync([FromBody] SignupRequestDto request)
{
var result = await _authService.SignupAsync(request);
return Ok(ApiResponse<SignupResponseDto>.Success(result, "회원가입 완료. 이메일 인증이 필요합니다."));
}
[HttpPost("email/check")]
[AllowAnonymous]
[SwaggerOperation(
Summary = "이메일 중복 체크",
Description = "회원가입 전 이메일 사용 가능 여부를 확인합니다.")]
[SwaggerResponse(200, "이메일 중복 체크 성공", typeof(ApiResponse<EmailCheckResponseDto>))]
[SwaggerResponse(400, "잘못된 요청")]
public async Task<IActionResult> CheckEmailAsync([FromBody] EmailCheckRequestDto request)
{
var result = await _authService.CheckEmailAsync(request);
return Ok(ApiResponse<EmailCheckResponseDto>.Success(result));
}
[HttpPost("login")]
[AllowAnonymous]
[SwaggerOperation(
Summary = "관리자 로그인",
Description = "이메일과 비밀번호로 로그인하여 JWT 토큰을 발급받습니다.")]
[SwaggerResponse(200, "로그인 성공", typeof(ApiResponse<LoginResponseDto>))]
[SwaggerResponse(401, "로그인 실패")]
public async Task<IActionResult> LoginAsync([FromBody] LoginRequestDto request)
{
var result = await _authService.LoginAsync(request);
return Ok(ApiResponse<LoginResponseDto>.Success(result));
}
[HttpPost("token/refresh")]
[AllowAnonymous]
[SwaggerOperation(
Summary = "토큰 갱신",
Description = "Refresh Token을 사용하여 새로운 Access Token과 Refresh Token을 발급받습니다.")]
[SwaggerResponse(200, "토큰 갱신 성공", typeof(ApiResponse<TokenRefreshResponseDto>))]
[SwaggerResponse(401, "유효하지 않거나 만료된 Refresh Token")]
public async Task<IActionResult> RefreshTokenAsync([FromBody] TokenRefreshRequestDto request)
{
var result = await _authService.RefreshTokenAsync(request);
return Ok(ApiResponse<TokenRefreshResponseDto>.Success(result));
}
[HttpPost("logout")]
[Authorize]
[SwaggerOperation(
Summary = "로그아웃",
Description = "현재 로그인된 관리자의 Refresh Token을 무효화합니다.")]
[SwaggerResponse(200, "로그아웃 성공")]
[SwaggerResponse(401, "인증되지 않은 요청")]
public async Task<IActionResult> LogoutAsync()
{
var adminIdClaim = User.FindFirst("adminId")?.Value;
if (string.IsNullOrEmpty(adminIdClaim) || !long.TryParse(adminIdClaim, out var adminId))
{
return Unauthorized(ApiResponse<object>.Fail("101", "인증 정보가 유효하지 않습니다."));
}
await _authService.LogoutAsync(adminId);
return Ok(ApiResponse.Success());
}
[HttpPost("password/change")]
[Authorize]
[SwaggerOperation(
Summary = "비밀번호 변경",
Description = "현재 로그인된 관리자의 비밀번호를 변경합니다.")]
[SwaggerResponse(200, "비밀번호 변경 성공")]
[SwaggerResponse(400, "현재 비밀번호 불일치")]
[SwaggerResponse(401, "인증되지 않은 요청")]
public async Task<IActionResult> ChangePasswordAsync([FromBody] ChangePasswordRequestDto request)
{
var adminIdClaim = User.FindFirst("adminId")?.Value;
if (string.IsNullOrEmpty(adminIdClaim) || !long.TryParse(adminIdClaim, out var adminId))
{
return Unauthorized(ApiResponse<object>.Fail("101", "인증 정보가 유효하지 않습니다."));
}
await _authService.ChangePasswordAsync(adminId, request);
return Ok(ApiResponse.Success());
}
}