improvement: 로그인 분기 계약 확장 (#177) #204

Merged
seonkyu.kim merged 1 commits from improvement/#177-login-next-action into develop 2026-02-25 01:21:05 +00:00
3 changed files with 55 additions and 2 deletions
Showing only changes of commit 859eabd83c - Show all commits

View File

@ -51,7 +51,9 @@ public class AuthController : ControllerBase
[AllowAnonymous] [AllowAnonymous]
[SwaggerOperation( [SwaggerOperation(
Summary = "관리자 로그인", Summary = "관리자 로그인",
Description = "이메일과 비밀번호로 로그인하여 JWT 토큰을 발급받습니다.")] Description = "이메일과 비밀번호로 로그인하여 JWT 토큰을 발급받습니다. " +
"응답의 nextAction으로 화면 분기: GO_DASHBOARD(대시보드), VERIFY_EMAIL(이메일 인증 필요). " +
"미인증 유저는 verifySessionId와 emailSent가 함께 반환됩니다.")]
[SwaggerResponse(200, "로그인 성공", typeof(ApiResponse<LoginResponseDto>))] [SwaggerResponse(200, "로그인 성공", typeof(ApiResponse<LoginResponseDto>))]
[SwaggerResponse(401, "로그인 실패")] [SwaggerResponse(401, "로그인 실패")]
public async Task<IActionResult> LoginAsync([FromBody] LoginRequestDto request) public async Task<IActionResult> LoginAsync([FromBody] LoginRequestDto request)

View File

@ -13,6 +13,18 @@ public class LoginResponseDto
[JsonPropertyName("expires_in")] [JsonPropertyName("expires_in")]
public int ExpiresIn { get; set; } public int ExpiresIn { get; set; }
[JsonPropertyName("next_action")]
public string NextAction { get; set; } = string.Empty;
[JsonPropertyName("email_verified")]
public bool EmailVerified { get; set; }
[JsonPropertyName("verify_session_id")]
public string? VerifySessionId { get; set; }
[JsonPropertyName("email_sent")]
public bool? EmailSent { get; set; }
[JsonPropertyName("admin")] [JsonPropertyName("admin")]
public AdminInfoDto? Admin { get; set; } public AdminInfoDto? Admin { get; set; }
} }

View File

@ -155,12 +155,51 @@ public class AuthService : IAuthService
_adminRepository.Update(admin); _adminRepository.Update(admin);
await _unitOfWork.SaveChangesAsync(); await _unitOfWork.SaveChangesAsync();
// 6. 응답 반환 // 6. 분기 판정 + verify session 생성
var nextAction = "GO_DASHBOARD";
string? verifySessionId = null;
bool? emailSent = null;
if (!admin.EmailVerified)
{
nextAction = "VERIFY_EMAIL";
// 인증코드 생성/저장
var verificationCode = Random.Shared.Next(100000, 999999).ToString();
await _tokenStore.StoreAsync(
$"email_verify:{admin.Email}",
verificationCode,
TimeSpan.FromHours(1));
// Verify Session 생성
verifySessionId = Guid.NewGuid().ToString("N");
await _tokenStore.StoreAsync(
$"verify_session:{verifySessionId}",
admin.Email,
TimeSpan.FromHours(1));
// 메일 발송 (실패해도 로그인은 유지)
emailSent = true;
try
{
await _emailService.SendVerificationCodeAsync(admin.Email, verificationCode);
}
catch
{
emailSent = false;
}
}
// 7. 응답 반환
return new LoginResponseDto return new LoginResponseDto
{ {
AccessToken = accessToken, AccessToken = accessToken,
RefreshToken = refreshToken, RefreshToken = refreshToken,
ExpiresIn = _jwtSettings.ExpiryMinutes * 60, ExpiresIn = _jwtSettings.ExpiryMinutes * 60,
NextAction = nextAction,
EmailVerified = admin.EmailVerified,
VerifySessionId = verifySessionId,
EmailSent = emailSent,
Admin = new AdminInfoDto Admin = new AdminInfoDto
{ {
AdminCode = admin.AdminCode, AdminCode = admin.AdminCode,