forked from AcaMate/AcaMate_API
[✨] 로그인 동작 및 Repository 동작 변경
1. 로그인 되었을 경우 화면 표기 변경 1.1. 사용자 이름 보내주기 1.2. 서버에서 직접적인 크라이언트 쿠키 저장이 아닌 서버는 뒤의 값으로 간섭하게 변경
This commit is contained in:
parent
a9462ca9b5
commit
669f22d365
|
@ -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비트
|
||||
|
|
|
@ -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<IActionResult> 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<LoginAPIResponse>(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();
|
||||
}
|
||||
|
|
|
@ -106,10 +106,14 @@ namespace Back.Program.Controllers.V1
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[HttpGet("auth/session")]
|
||||
[CustomOperation("세션 정보 확인", "세션 정보 확인", "사용자")]
|
||||
public async Task<IActionResult> GetSessionData()
|
||||
{
|
||||
string summary = _repositoryService.ReadSummary(typeof(UserController), "GetSessionData");
|
||||
var result = await _userService.GetSessionData(summary);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<object>("000", $"[{summary}], 토큰 생성 완료", new { accsee = access });
|
||||
return APIResponse.Send<object>("000", $"[{summary}], 토큰 생성 완료", new { access = access });
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,6 @@ namespace Back.Program.Services.V1.Interfaces
|
|||
Task<APIResponseStatus<object>> Logout(string summary, string token);
|
||||
Task<APIResponseStatus<object>> Cancel(string summary, string token);
|
||||
Task<APIResponseStatus<object>> GetAcademy(string summary, string token);
|
||||
|
||||
Task<APIResponseStatus<object>> GetSessionData(string summary);
|
||||
}
|
||||
}
|
|
@ -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<IUserService> 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<APIResponseStatus<object>> GetUser(string summary, string token)
|
||||
|
@ -234,5 +240,83 @@ namespace Back.Program.Services.V1
|
|||
_logger.LogInformation($"[{summary}]: 성공");
|
||||
return APIResponse.Send<object>("000", $"[{summary}], 정상.", academyList);
|
||||
}
|
||||
|
||||
public async Task<APIResponseStatus<object>> 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<object>("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<object>("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<JsonElement>(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<object>("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<object>("203", "사용자 정보를 찾을 수 없습니다", new { name = "" });
|
||||
}
|
||||
|
||||
_logger.LogInformation($"[{summary}] 세션 데이터 조회 성공: {user.name}");
|
||||
return APIResponse.Send<object>("000", $"[{summary}], 정상", new { name = user.name });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"[{summary}] 세션 데이터 조회 중 오류: {ex.Message}");
|
||||
_logger.LogError($"[{summary}] 스택 트레이스: {ex.StackTrace}");
|
||||
return APIResponse.InternalSeverError($"[{summary}], 세션 데이터 조회 실패");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user