Files
Genesis_GameServer/GameServer/Controllers/Portfolio/PortfolioAuthController.cs
2026-09-03 19:18:46 +09:00

107 lines
4.0 KiB
C#

using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using GameServer.Models;
using GameServer.Models.Portfolio;
using GameServer.Services;
namespace GameServer.Controllers.Portfolio
{
/// <summary>
/// 포트폴리오 관리자 로그인 / 로그아웃 / 세션 확인 API.
/// 게임 API(/myGame/*) 와는 완전히 분리된 /api/portfolio/auth 경로를 사용한다.
/// </summary>
[ApiController]
[Route("api/portfolio/auth")]
public class PortfolioAuthController : ControllerBase
{
private readonly PortfolioAdminAuth _auth;
public PortfolioAuthController(PortfolioAdminAuth auth)
{
_auth = auth;
}
/// <summary>비밀번호로 로그인하고 관리자 쿠키를 발급한다.</summary>
[HttpPost("login")]
[EnableRateLimiting("portfolio-login")]
public async Task<IActionResult> Login([FromBody] LoginRequestDto request)
{
// 비밀번호가 아직 설정되지 않았다면 503 으로 안내한다.
if (!_auth.IsConfigured)
{
return StatusCode(StatusCodes.Status503ServiceUnavailable, new ApiResponse<AuthStateDto>
{
Data = new AuthStateDto { Authenticated = false },
Message = "관리자 비밀번호가 설정되지 않았습니다. appsettings.json의 Portfolio:AdminPassword 를 변경해 주세요."
});
}
if (!_auth.Verify(request?.Password))
{
return StatusCode(StatusCodes.Status401Unauthorized, new ApiResponse<AuthStateDto>
{
Data = new AuthStateDto { Authenticated = false },
Message = "비밀번호가 올바르지 않습니다."
});
}
// 관리자 신원 발급 (7일 유지)
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "admin"),
new Claim(ClaimTypes.Role, "admin")
};
var identity = new ClaimsIdentity(claims, PortfolioAdminAuth.CookieScheme);
var principal = new ClaimsPrincipal(identity);
var props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.AddDays(7)
};
await HttpContext.SignInAsync(PortfolioAdminAuth.CookieScheme, principal, props);
return Ok(new ApiResponse<AuthStateDto>
{
Data = new AuthStateDto { Authenticated = true },
Message = "로그인되었습니다."
});
}
/// <summary>관리자 쿠키를 만료시킨다. 언제 호출해도 200.</summary>
[HttpPost("logout")]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync(PortfolioAdminAuth.CookieScheme);
return Ok(new ApiResponse<AuthStateDto>
{
Data = new AuthStateDto { Authenticated = false },
Message = "로그아웃되었습니다."
});
}
/// <summary>
/// 현재 로그인 상태를 알려준다. 절대 401 을 돌려주지 않는다.
/// Message 에는 비밀번호 설정 여부("configured" / "not-configured")를 담아
/// 관리자 화면이 안내 문구를 띄울 수 있게 한다.
/// </summary>
[HttpGet("me")]
public async Task<IActionResult> Me()
{
var result = await HttpContext.AuthenticateAsync(PortfolioAdminAuth.CookieScheme);
bool authenticated = result.Succeeded && result.Principal?.Identity?.IsAuthenticated == true;
return Ok(new ApiResponse<AuthStateDto>
{
Data = new AuthStateDto { Authenticated = authenticated },
Message = _auth.IsConfigured ? "configured" : "not-configured"
});
}
}
}