Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public class CookieOAuth2AuthorizationRequestRepository
implements AuthorizationRequestRepository<OAuth2AuthorizationRequest> {

private static final String COOKIE_NAME = "oauth2_auth_request";
public static final String REDIRECT_TARGET_COOKIE = "redirect_target";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

"local" 및 "deploy"와 같은 환경 식별 문자열을 상수로 정의하여 관리하면 오타를 방지하고 OAuth2LoginSuccessHandler 등 다른 클래스에서 안전하게 재사용할 수 있습니다.

Suggested change
public static final String REDIRECT_TARGET_COOKIE = "redirect_target";
public static final String REDIRECT_TARGET_COOKIE = "redirect_target";
public static final String TARGET_LOCAL = "local";
public static final String TARGET_DEPLOY = "deploy";

public static final String TARGET_LOCAL = "local";
public static final String TARGET_DEPLOY = "deploy";
private static final int COOKIE_EXPIRE_SECONDS = 180; // 3분

// 쿠키에서 Authorization Request 조회
Expand All @@ -30,10 +33,19 @@ public void saveAuthorizationRequest(
HttpServletResponse response) {
if (authorizationRequest == null) {
CookieUtils.deleteCookie(request, response, COOKIE_NAME);
CookieUtils.deleteCookie(request, response, REDIRECT_TARGET_COOKIE);
return;
}
CookieUtils.addCookie(response, COOKIE_NAME,
CookieUtils.serialize(authorizationRequest), COOKIE_EXPIRE_SECONDS);

// Referer 헤더로 출발지(local/deploy) 판단 후 쿠키 저장
// contains 대신 startsWith로 호스트 부분만 검사 (http://attacker.com/localhost 같은 케이스 차단)
String referer = request.getHeader("Referer");
boolean isLocal = referer != null
&& (referer.startsWith("http://localhost") || referer.startsWith("https://localhost"));
String target = isLocal ? TARGET_LOCAL : TARGET_DEPLOY;
CookieUtils.addCookie(response, REDIRECT_TARGET_COOKIE, target, COOKIE_EXPIRE_SECONDS);
}

// 쿠키에서 Authorization Request 꺼내고 삭제
Expand All @@ -43,6 +55,7 @@ public OAuth2AuthorizationRequest removeAuthorizationRequest(
HttpServletResponse response) {
OAuth2AuthorizationRequest authorizationRequest = loadAuthorizationRequest(request);
CookieUtils.deleteCookie(request, response, COOKIE_NAME);
// REDIRECT_TARGET_COOKIE는 SuccessHandler에서 사용 후 삭제
return authorizationRequest;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.hansung.zigma.global.oauth;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.hansung.zigma.global.jwt.CustomUserDetails;
import org.hansung.zigma.global.jwt.JwtTokenProvider;
import org.hansung.zigma.global.util.CookieUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
Expand All @@ -20,8 +22,11 @@ public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHan

private final JwtTokenProvider jwtTokenProvider;

@Value("${app.oauth2.front-redirect-uri}")
private String redirectUri;
@Value("${app.oauth2.front-redirect-uri.local}")
private String localRedirectUri;

@Value("${app.oauth2.front-redirect-uri.deploy}")
private String deployRedirectUri;

@Override
public void onAuthenticationSuccess(
Expand All @@ -34,6 +39,17 @@ public void onAuthenticationSuccess(
userDetails.getUser().getId().toString()
);

// 출발지(local/deploy) 쿠키 보고 리다이렉트 URI 선택, 누락 시 deploy 폴백
String target = CookieUtils.getCookie(request,
CookieOAuth2AuthorizationRequestRepository.REDIRECT_TARGET_COOKIE)
.map(Cookie::getValue)
.orElse(CookieOAuth2AuthorizationRequestRepository.TARGET_DEPLOY);
String redirectUri = CookieOAuth2AuthorizationRequestRepository.TARGET_LOCAL.equals(target)
? localRedirectUri : deployRedirectUri;

CookieUtils.deleteCookie(request, response,
CookieOAuth2AuthorizationRequestRepository.REDIRECT_TARGET_COOKIE);

String targetUrl = UriComponentsBuilder.fromUriString(redirectUri)
.queryParam("accessToken", accessToken)
.build().toUriString();
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ jwt.access.expiration = ${JWT_ACCESS_EXPIRATION}
jwt.refresh.expiration = ${JWT_REFRESH_EXPIRATION}

# Frontend
app.oauth2.front-redirect-uri=https://z-igma.vercel.app//oauth/callback
app.oauth2.front-redirect-uri.local=http://localhost:5173/oauth/callback
app.oauth2.front-redirect-uri.deploy=https://z-igma.vercel.app/oauth/callback

# Web Push
web-push.vapid-public-key=${WEB_PUSH_VAPID_PUBLIC_KEY:}
Expand Down
Loading