From 669f22d3652222ec23a6fb1975ca8abd301d92c8 Mon Sep 17 00:00:00 2001 From: SEAN-59 Date: Wed, 11 Jun 2025 15:14:42 +0900 Subject: [PATCH] =?UTF-8?q?[=E2=9C=A8]=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=8F=99=EC=9E=91=20=EB=B0=8F=20Repository=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 로그인 되었을 경우 화면 표기 변경 1.1. 사용자 이름 보내주기 1.2. 서버에서 직접적인 크라이언트 쿠키 저장이 아닌 서버는 뒤의 값으로 간섭하게 변경 --- Program/Common/Auth/JwtTokenService.cs | 3 + Program/Controllers/V1/OutController.cs | 59 +++++++++---- Program/Controllers/V1/UserController.cs | 12 ++- Program/Services/V1/AppService.cs | 6 +- .../Services/V1/Interfaces/IUserService.cs | 2 +- Program/Services/V1/UserService.cs | 86 ++++++++++++++++++- 6 files changed, 144 insertions(+), 24 deletions(-) diff --git a/Program/Common/Auth/JwtTokenService.cs b/Program/Common/Auth/JwtTokenService.cs index caa0e27..cd5e0d3 100644 --- a/Program/Common/Auth/JwtTokenService.cs +++ b/Program/Common/Auth/JwtTokenService.cs @@ -22,6 +22,8 @@ namespace Back.Program.Common.Auth _logger = logger; } + + // JWT 토큰 생성 public string GenerateJwtToken(string jwtKey)//, string role) { // 1. 클레임(Claim) 설정 - 필요에 따라 추가 정보도 포함 @@ -53,6 +55,7 @@ namespace Back.Program.Common.Auth return new JwtSecurityTokenHandler().WriteToken(token); } + // 리프레시 토큰 생성 public RefreshToken GenerateRefreshToken(string uid) { var randomNumber = new byte[32]; // 256비트 diff --git a/Program/Controllers/V1/OutController.cs b/Program/Controllers/V1/OutController.cs index 6801f34..eebdfc5 100644 --- a/Program/Controllers/V1/OutController.cs +++ b/Program/Controllers/V1/OutController.cs @@ -10,6 +10,8 @@ using Back.Program.Models.APIResponses; namespace Back.Program.Controllers; + +// TO-DO: 여기 controller, service, repository 분리 필요 [ApiController] [Route("/api/v1/out/user")] [ApiExplorerSettings(GroupName = "외부 동작(사용자)")] @@ -48,48 +50,63 @@ public class OutController: ControllerBase [HttpGet("kakao/redirect")] public async Task RedirectFromKakao([FromQuery] string code) { + _logger.LogInformation("카카오 리다이렉트 시작"); var (success, response) = await _kakaoService.Redirect(code); - Console.WriteLine($"리다이렉트 : {response}"); + _logger.LogInformation($"리다이렉트 결과: {success}, 응답: {response}"); + if (success) { var (idSuccess, idResponse) = await _kakaoService.UserMe(response); + _logger.LogInformation($"사용자 정보 조회 결과: {idSuccess}, 응답: {idResponse}"); + if (idSuccess) { var json = JsonDocument.Parse(idResponse); if (json.RootElement.TryGetProperty("id", out var idElement)) { var snsId = idElement.ToString(); - Console.WriteLine($"ID = {snsId}"); + _logger.LogInformation($"카카오 ID: {snsId}"); + var loginResult = await _userService.Login("SNS Login", "ST01", snsId); - Console.WriteLine($"login = {loginResult.JsonToString()}"); + _logger.LogInformation($"로그인 결과: {loginResult.JsonToString()}"); + if (loginResult.status.code == "000") { - var data = loginResult.data as LoginAPIResponse ?? new LoginAPIResponse(); + var data = JsonSerializer.Deserialize(JsonSerializer.Serialize(loginResult.data)); + _logger.LogInformation($"로그인 데이터: {JsonSerializer.Serialize(data)}"); + if (data != null) { string token = data.token; string refresh = data.refresh; + _logger.LogInformation($"토큰 저장 시도 - token: {token}, refresh: {refresh}"); + if (await _sessionService.SetString("token", token) && await _sessionService.SetString("refresh", refresh)) { + _logger.LogInformation("세션 저장 성공"); var (hasPath, redirectPath) = await _sessionService.GetString("redirectPath"); await _sessionService.Remove("redirectPath"); // 사용 후 세션에서 제거 - // 로그인 성공 flag 쿠키 저장 - Response.Cookies.Append("IsLogin", "true", new CookieOptions - { - HttpOnly = false, - Secure = true, - SameSite = SameSiteMode.Lax, - Path = "/", - Expires = DateTime.Now.AddDays(1) - }); - return Redirect(hasPath && !string.IsNullOrEmpty(redirectPath) ? redirectPath : "/about"); + var redirectUrl = hasPath && !string.IsNullOrEmpty(redirectPath) + ? $"{redirectPath}?auth=true" + : "/about?auth=true"; + _logger.LogInformation($"리다이렉트 URL: {redirectUrl}"); + return Redirect(redirectUrl); } + else + { + _logger.LogError("세션 저장 실패"); + } + } + else + { + _logger.LogError("로그인 데이터가 null입니다"); } } else if (loginResult.status.code == "001") { + _logger.LogInformation("회원가입 필요"); if (await _sessionService.SetString("snsId", snsId)) { return Redirect("/auth/register"); @@ -97,11 +114,23 @@ public class OutController: ControllerBase } else { + _logger.LogError($"로그인 실패: {loginResult.status.message}"); return BadRequest(new { error = "로그인 실패", message = loginResult.status.message }); } } + else + { + _logger.LogError("카카오 ID를 찾을 수 없습니다"); + } } - Console.WriteLine($"ID_res = {idResponse}"); + else + { + _logger.LogError($"사용자 정보 조회 실패: {idResponse}"); + } + } + else + { + _logger.LogError($"카카오 리다이렉트 실패: {response}"); } return BadRequest(); } diff --git a/Program/Controllers/V1/UserController.cs b/Program/Controllers/V1/UserController.cs index 93fe848..18fc255 100644 --- a/Program/Controllers/V1/UserController.cs +++ b/Program/Controllers/V1/UserController.cs @@ -106,10 +106,14 @@ namespace Back.Program.Controllers.V1 return Ok(result); } - - - - + [HttpGet("auth/session")] + [CustomOperation("세션 정보 확인", "세션 정보 확인", "사용자")] + public async Task GetSessionData() + { + string summary = _repositoryService.ReadSummary(typeof(UserController), "GetSessionData"); + var result = await _userService.GetSessionData(summary); + return Ok(result); + } } } diff --git a/Program/Services/V1/AppService.cs b/Program/Services/V1/AppService.cs index 32aeb03..538c8b6 100644 --- a/Program/Services/V1/AppService.cs +++ b/Program/Services/V1/AppService.cs @@ -158,11 +158,11 @@ public class AppService: IAppService { var refreshToken = await _appRepository.FindRefreshToken(refresh); if (refreshToken == null) return APIResponse.InvalidInputError($"[{summary}] : 리프레시 토큰 문제"); - if (refreshToken.revoke_Date < DateTime.Now) return APIResponse.InvalidInputError($"[{summary}] : 리프레시 토큰 만료"); - if (refreshToken.expire_date < DateTime.Now) return APIResponse.InvalidInputError($"[{summary}] : 리프레시 토큰 폐기"); + if (refreshToken.revoke_Date != null) return APIResponse.InvalidInputError($"[{summary}] : 리프레시 토큰 폐기"); + if (refreshToken.expire_date < DateTime.Now) return APIResponse.InvalidInputError($"[{summary}] : 리프레시 토큰 만료"); string access = _jwtTokenService.GenerateJwtToken(refreshToken.uid); - return APIResponse.Send("000", $"[{summary}], 토큰 생성 완료", new { accsee = access }); + return APIResponse.Send("000", $"[{summary}], 토큰 생성 완료", new { access = access }); } } \ No newline at end of file diff --git a/Program/Services/V1/Interfaces/IUserService.cs b/Program/Services/V1/Interfaces/IUserService.cs index ebe0df7..68df934 100644 --- a/Program/Services/V1/Interfaces/IUserService.cs +++ b/Program/Services/V1/Interfaces/IUserService.cs @@ -11,6 +11,6 @@ namespace Back.Program.Services.V1.Interfaces Task> Logout(string summary, string token); Task> Cancel(string summary, string token); Task> GetAcademy(string summary, string token); - + Task> GetSessionData(string summary); } } \ No newline at end of file diff --git a/Program/Services/V1/UserService.cs b/Program/Services/V1/UserService.cs index 418e560..8e13cca 100644 --- a/Program/Services/V1/UserService.cs +++ b/Program/Services/V1/UserService.cs @@ -4,6 +4,7 @@ using Back.Program.Common.Model; using Back.Program.Models.Entities; using Back.Program.Repositories.V1.Interfaces; using Back.Program.Services.V1.Interfaces; +using System.Text.Json; namespace Back.Program.Services.V1 { @@ -14,16 +15,21 @@ namespace Back.Program.Services.V1 private readonly JwtTokenService _jwtTokenService; private readonly IRepositoryService _repositoryService; private readonly ILogRepository _logRepository; + private readonly ISessionService _sessionService; + private readonly IAppService _appService; public UserService(ILogger logger, IUserRepository userRepository, JwtTokenService jwtTokenService, - IRepositoryService repositoryService, ILogRepository logRepository) + IRepositoryService repositoryService, ILogRepository logRepository, + ISessionService sessionService, IAppService appService) { _logger = logger; _userRepository = userRepository; _jwtTokenService = jwtTokenService; _repositoryService = repositoryService; _logRepository = logRepository; + _sessionService = sessionService; + _appService = appService; } public async Task> GetUser(string summary, string token) @@ -234,5 +240,83 @@ namespace Back.Program.Services.V1 _logger.LogInformation($"[{summary}]: 성공"); return APIResponse.Send("000", $"[{summary}], 정상.", academyList); } + + public async Task> GetSessionData(string summary) + { + try + { + _logger.LogInformation($"[{summary}] 세션 데이터 조회 시작"); + + // 1. 세션에서 토큰 가져오기 + var (result, token) = await _sessionService.GetString("token"); + _logger.LogInformation($"[{summary}] 세션에서 토큰 가져오기 결과: {result}, 토큰: {token}"); + + if (!result || string.IsNullOrEmpty(token)) + { + _logger.LogWarning($"[{summary}] 세션에 토큰이 없습니다"); + return APIResponse.Send("200", "세션에 토큰이 없습니다", new { name = "" }); + } + + // 2. 토큰 검증 + var validToken = await _jwtTokenService.ValidateToken(token); + _logger.LogInformation($"[{summary}] 토큰 검증 결과: {validToken != null}"); + + if (validToken == null) + { + // 3. 토큰이 유효하지 않으면 리프레시 토큰으로 새 토큰 발급 시도 + var (refreshResult, refreshToken) = await _sessionService.GetString("refresh"); + _logger.LogInformation($"[{summary}] 리프레시 토큰 가져오기 결과: {refreshResult}, 토큰: {refreshToken}"); + + if (!refreshResult || string.IsNullOrEmpty(refreshToken)) + { + _logger.LogWarning($"[{summary}] 리프레시 토큰이 없습니다"); + return APIResponse.Send("201", "리프레시 토큰이 없습니다", new { name = "" }); + } + + // 4. 리프레시 토큰으로 새 토큰 발급 + var retryResult = await _appService.RetryAccess(summary, refreshToken); + _logger.LogInformation($"[{summary}] 토큰 재발급 결과: {retryResult.status.code}"); + + if (retryResult.status.code == "000") + { + // 5. 새 토큰을 세션에 저장 + var data = JsonSerializer.Deserialize(JsonSerializer.Serialize(retryResult.data)); + var newToken = data.GetProperty("access").GetString(); + await _sessionService.SetString("token", newToken); + _logger.LogInformation($"[{summary}] 새 토큰 세션 저장 완료"); + + // 6. 새 토큰으로 사용자 정보 조회 + validToken = await _jwtTokenService.ValidateToken(newToken); + } + else + { + _logger.LogWarning($"[{summary}] 토큰 갱신 실패: {retryResult.status.message}"); + return APIResponse.Send("202", "토큰 갱신 실패", new { name = "" }); + } + } + + // 7. 최종적으로 유효한 토큰으로 사용자 정보 조회 + var uid = validToken.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? string.Empty; + _logger.LogInformation($"[{summary}] 사용자 ID: {uid}"); + + var user = await _userRepository.FindUser(uid); + _logger.LogInformation($"[{summary}] 사용자 정보 조회 결과: {user != null}"); + + if (user == null) + { + _logger.LogWarning($"[{summary}] 사용자 정보를 찾을 수 없습니다"); + return APIResponse.Send("203", "사용자 정보를 찾을 수 없습니다", new { name = "" }); + } + + _logger.LogInformation($"[{summary}] 세션 데이터 조회 성공: {user.name}"); + return APIResponse.Send("000", $"[{summary}], 정상", new { name = user.name }); + } + catch (Exception ex) + { + _logger.LogError($"[{summary}] 세션 데이터 조회 중 오류: {ex.Message}"); + _logger.LogError($"[{summary}] 스택 트레이스: {ex.StackTrace}"); + return APIResponse.InternalSeverError($"[{summary}], 세션 데이터 조회 실패"); + } + } } } \ No newline at end of file