feat: harden auth ops and deployment baseline

This commit is contained in:
2026-06-27 10:53:53 +09:00
parent a6ca30eec8
commit 28060b71be
41 changed files with 714 additions and 208 deletions
+63 -2
View File
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using TaxBaik.Web.Services;
namespace TaxBaik.Web.Controllers;
@@ -18,14 +19,61 @@ public class AuthController : ControllerBase
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
if (string.IsNullOrWhiteSpace(request.Username) || string.IsNullOrWhiteSpace(request.Password))
return BadRequest(new { message = "Username and password are required" });
return BadRequest(new ProblemDetails { Title = "로그인 정보가 필요합니다.", Status = StatusCodes.Status400BadRequest });
var token = await _authService.AuthenticateAndGenerateTokenAsync(request.Username, request.Password);
if (token == null)
return Unauthorized(new { message = "Invalid username or password" });
return Unauthorized(new ProblemDetails { Title = "아이디 또는 비밀번호가 올바르지 않습니다.", Status = StatusCodes.Status401Unauthorized });
return Ok(new { token, expiresIn = 28800 });
}
[HttpPost("change-password")]
[Microsoft.AspNetCore.Authorization.Authorize]
public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequest request)
{
var username = User.FindFirstValue(ClaimTypes.Name);
if (string.IsNullOrWhiteSpace(username))
return Unauthorized(new ProblemDetails { Title = "인증 정보가 올바르지 않습니다.", Status = StatusCodes.Status401Unauthorized });
try
{
var changed = await _authService.ChangePasswordAsync(username, request.CurrentPassword, request.NewPassword);
if (!changed)
return Unauthorized(new ProblemDetails { Title = "현재 비밀번호가 올바르지 않습니다.", Status = StatusCodes.Status401Unauthorized });
return Ok(new { message = "비밀번호가 변경되었습니다." });
}
catch (ArgumentException ex)
{
return BadRequest(new ProblemDetails { Title = ex.Message, Status = StatusCodes.Status400BadRequest });
}
}
[HttpPost("reset-password")]
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordRequest request)
{
try
{
var reset = await _authService.ResetPasswordAsync(request.Username, request.NewPassword, request.ResetToken);
if (!reset)
return Unauthorized(new ProblemDetails { Title = "재설정 토큰 또는 사용자 정보가 올바르지 않습니다.", Status = StatusCodes.Status401Unauthorized });
return Ok(new { message = "비밀번호가 재설정되었습니다." });
}
catch (InvalidOperationException)
{
return StatusCode(StatusCodes.Status503ServiceUnavailable, new ProblemDetails
{
Title = "비밀번호 재설정 토큰이 서버에 설정되어 있지 않습니다.",
Status = StatusCodes.Status503ServiceUnavailable
});
}
catch (ArgumentException ex)
{
return BadRequest(new ProblemDetails { Title = ex.Message, Status = StatusCodes.Status400BadRequest });
}
}
}
public class LoginRequest
@@ -33,3 +81,16 @@ public class LoginRequest
public string Username { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
public class ChangePasswordRequest
{
public string CurrentPassword { get; set; } = string.Empty;
public string NewPassword { get; set; } = string.Empty;
}
public class ResetPasswordRequest
{
public string Username { get; set; } = string.Empty;
public string NewPassword { get; set; } = string.Empty;
public string ResetToken { get; set; } = string.Empty;
}