-
Notifications
You must be signed in to change notification settings - Fork 0
refactor(user): 토큰 전달 방식 수정 #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "feature/#53-\uCE74\uCE74\uC624\uB85C\uADF8\uC778_\uB9AC\uD329\uD1A0\uB9C1"
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
|
||
| import jakarta.servlet.ServletException; | ||
| import jakarta.servlet.http.Cookie; | ||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import lombok.RequiredArgsConstructor; | ||
|
|
@@ -28,7 +29,6 @@ | |
| // 1. JWT 토큰 발급 | ||
| // - 이때, JWT payload는 보안상 최소한의 정보(userId, role)만 담겠다 | ||
| // 2. refreshToken만 DB에 저장 | ||
| // 3. JSON 응답으로, accessToken과 refreshToken 을 반환해준다. | ||
| @Component | ||
| @RequiredArgsConstructor | ||
| @Slf4j | ||
|
|
@@ -40,42 +40,30 @@ public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHan | |
| public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, | ||
| Authentication authentication) throws IOException { | ||
|
|
||
| // 1. CustomOAuth2UserService에서 설정한 OAuth2User 정보 가져오기 | ||
| CustomOAuth2User customUserDetails = (CustomOAuth2User)authentication.getPrincipal(); | ||
|
|
||
| CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal(); | ||
| User user = customUserDetails.getUser(); | ||
| Long userId = customUserDetails.getUserId(); | ||
| String email = customUserDetails.getName(); | ||
|
|
||
| Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); | ||
| Iterator<? extends GrantedAuthority> iterator = authorities.iterator(); | ||
| GrantedAuthority auth = iterator.next(); | ||
|
|
||
| String role = auth.getAuthority(); | ||
| String role = authentication.getAuthorities().iterator().next().getAuthority(); | ||
|
|
||
| log.info("user, userId, email, role :: {} {} {} {}", user, userId, email, role); | ||
| // JWT 발급 | ||
| String accessToken = jwtUtil.createAccessToken("accessToken", userId, role, 30 * 60 * 1000L); // 30분 | ||
| String refreshToken = jwtUtil.createRefreshToken("refreshToken", userId, 30L * 24 * 60 * 60 * 1000L); // 30일 | ||
|
|
||
| // 2. 1)의 사용자 정보를 담아, accessToken과 refreshToken 발행 | ||
| String accessToken = jwtUtil.createAccessToken("accessToken", userId, role, 30 * 60 * 1000L); // 유효기간 30분 | ||
| String refreshToken = jwtUtil.createRefreshToken("refreshToken", userId, | ||
| 30 * 24 * 60 * 60 * 1000L); // 유효기간 30일 | ||
|
|
||
| // 3. refreshToken을 DB에 저장 | ||
| // 1. refreshToken을 DB에 저장 | ||
| Token refreshTokenEntity = Token.toEntity(user, refreshToken, LocalDateTime.now().plusDays(30)); | ||
| tokenRepository.save(refreshTokenEntity); | ||
|
|
||
| // 4. JSON 응답으로, accessToken과 refreshToken 을 반환해준다. | ||
| response.setContentType("application/json"); | ||
| response.setCharacterEncoding("utf-8"); | ||
|
|
||
| ObjectMapper objectMapper = new ObjectMapper(); // 객체 -> json 문자열로 변환 | ||
| String body = objectMapper.writeValueAsString( | ||
| Map.of( | ||
| "accessToken", accessToken, | ||
| "refreshToken", refreshToken | ||
| ) | ||
| ); | ||
| response.getWriter().write(body); | ||
| // 2. refreshToken을 HttpOnly 쿠키로 설정 | ||
| Cookie refreshTokenCookie = new Cookie("refreshToken", refreshToken); | ||
| refreshTokenCookie.setHttpOnly(true); // JS 접근 불가 | ||
| refreshTokenCookie.setSecure(false); // 운영환경 https라면 true | ||
| refreshTokenCookie.setPath("/"); | ||
| refreshTokenCookie.setMaxAge(30 * 24 * 60 * 60); // 30일 | ||
| response.addCookie(refreshTokenCookie); | ||
|
|
||
| // 3. 프론트엔드로 리다이렉트 (accessToken만 쿼리로 전달) | ||
| String targetUrl = "http://localhost:5173/login/success?accessToken=" + accessToken; | ||
| response.sendRedirect(targetUrl); | ||
|
Comment on lines
+66
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 리다이렉트 URL 하드코딩 문제 해결 필요 현재 프론트엔드 URL이 하드코딩되어 있어서 개발/스테이징/운영 환경별로 다른 URL을 사용하기 어려울 것 같습니다. 또한 쿼리 파라미터로 access token을 전달하는 것도 보안상 고려사항이 있습니다. 다음과 같은 개선을 권장합니다: -// 3. 프론트엔드로 리다이렉트 (accessToken만 쿼리로 전달)
-String targetUrl = "http://localhost:5173/login/success?accessToken=" + accessToken;
-response.sendRedirect(targetUrl);
+// 3. 프론트엔드로 리다이렉트 (환경별 URL 설정)
+String frontendUrl = getFrontendUrl(); // 환경별 설정에서 가져오기
+String targetUrl = frontendUrl + "/login/success";
+
+// Access token도 쿠키로 전달 (보안 강화)
+Cookie accessTokenCookie = new Cookie("accessToken", accessToken);
+accessTokenCookie.setHttpOnly(false); // JS에서 접근 가능해야 함
+accessTokenCookie.setSecure(true);
+accessTokenCookie.setPath("/");
+accessTokenCookie.setMaxAge(30 * 60); // 30분
+response.addCookie(accessTokenCookie);
+
+response.sendRedirect(targetUrl);환경별 URL 설정을 위해 application.yml에 설정값 추가도 고려해보세요: app:
frontend:
url: ${FRONTEND_URL:http://localhost:5173}🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.