개요
- 카카오 소셜 로그인시, 특정 URI로 리다이렉트 시키는 로직에서 CORS가 발생한 문제에 대해 해결 할 수 있습니다
문제
- 현재 나는 아래의 프로세스 대로 진행중이다.
- 클라이언트가 /socialLogin?name=KAKAO로 요청한다.
- 서버는 OAuthRedirectController를 통해 카카오의 로그인을 타게한다.
- 카카오의 로그인이 성공적으로 마치면, 우리의 서버 redirectURL로 호출하여 마저 진행한다.
코드
OAuthRedirectController
@Controller
@Tag(name = "OAuth Login Redirect API")
public class OAuthRedirectController {
private static final String KAKAO_AUTH_URL = "https://kauth.kakao.com/oauth/authorize";
private static final String NAVER_AUTH_URL = "https://nid.naver.com/oauth2.0/authorize";
private static final String GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth";
private static final String REDIRECT_URI = OAuthConfig.getRedirectUrl(); // ✅ 정적 메서드로 가져오기
@Operation(
summary = "OAuth 로그인 페이지 리다이렉트",
description = "카카오, 네이버, 구글 로그인 페이지로 이동합니다."
)
@GetMapping("/redirectSocialLogin")
public void redirectSocialLogin(
@RequestParam("name") OAuthProviderName oAuthProviderName,
HttpServletResponse response
) {
try {
String clientId = getClientId(oAuthProviderName); // ✅ 동적으로 클라이언트 ID 가져오기
String url = switch (oAuthProviderName) {
case KAKAO -> KAKAO_AUTH_URL
+ "?response_type=code"
+ "&client_id=" + clientId
+ "&redirect_uri=" + REDIRECT_URI + "?oAuthProviderName=" + oAuthProviderName;
case NAVER -> NAVER_AUTH_URL
+ "?response_type=code"
+ "&client_id=" + clientId
+ "&redirect_uri=" + REDIRECT_URI + "?oAuthProviderName=" + oAuthProviderName;
case GOOGLE -> GOOGLE_AUTH_URL
+ "?response_type=code"
+ "&client_id=" + clientId
+ "&redirect_uri=" + REDIRECT_URI + "?oAuthProviderName=" + oAuthProviderName
+ "&scope=email%20profile"; // Google의 경우 추가 스코프 필요
default -> throw new OAuthException(OAUTH_NOT_FOUND_PROVIDER);
};
response.sendRedirect(url); // ✅ 직접 리다이렉트 수행 (CORS 문제 방지)
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// ✅ OAuth 제공자별 클라이언트 ID 동적 설정
private String getClientId(OAuthProviderName provider) {
return switch (provider) {
case KAKAO -> OAuthConfig.getKakaoClientId();
case NAVER -> OAuthConfig.getNaverClientId();
case GOOGLE -> OAuthConfig.getGoogleClientId();
default -> throw new OAuthException(OAUTH_NOT_FOUND_PROVIDER);
};
}
}
- 클라이언트에서 /socialLogin?name=KAKAO 이런식으로 요청이 들어오면, url로 리다이렉트 시키는 코드이다
스웨거 테스트
- 스웨거에서 직접 테스트를 해보자
- CORS가 발생되는 모습이다
무엇이 원인일까?
- 위와같이 생성된 URL은 하기와 같을것이다.
https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=cc96110225d43b82a2145de06d027dbc&redirect_uri=http://localhost:8080/auth/login/kakao
- 서버 -> 클라이언트로 요청시 CORS 정책이 적용되어 안됐던것이고
- 클라이언트 -> 클라이언트로 요청시 브라우저가 직접 해당 URL로 이동하는것이므로 CORS 문제가 발생되지 않았던것이다 (간단하군)
어떻게 해결했는가?
- 결국 브라우저의 보안정책의 CORS를 해결 하기위해서는, OAuth 제공자(카카오,네이버,구글)에서 우리의 서버를 통과시켜주어야하는데, 이 뜻은 우리 서버에서는 해결이 불가능 하다는 의미다.
- 따라서 만들어진 URL을 클라이언트에게 반환하는 형태로 일단 해결하였다.
시간이 좀 남았으니 다른문제도 봐보자
RedirectURL NULL로 찍히는 문제
- 현재 RedirectURL을 ENV에 설정한후
- dev,prd 프로필에 맞게 redirectURL을 따로 설정해놓았다
- OAuthConfig라는 빈에 등록될때, 각종 secretKey, redirectURL등을 저장시킨다
@Component
public class OAuthConfig {
@Value("${social.redirect.url}")
private String redirectUrl;
@Value("${social.kakao.client-id}")
private String kakaoClientId;
@Value("${social.naver.client-id}")
private String naverClientId;
@Value("${social.naver.client-secret}")
private String naverClientSecret;
@Value("${social.google.client-id}")
private String googleClientId;
@Value("${social.google.client-secret}")
private String googleClientSecret;
// ✅ Static 변수 선언 (초기화는 @PostConstruct에서 수행)
private static String STATIC_REDIRECT_URL;
private static String STATIC_KAKAO_CLIENT_ID;
private static String STATIC_NAVER_CLIENT_ID;
private static String STATIC_NAVER_CLIENT_SECRET;
private static String STATIC_GOOGLE_CLIENT_ID;
private static String STATIC_GOOGLE_CLIENT_SECRET;
@PostConstruct
public void init() {
STATIC_REDIRECT_URL = redirectUrl;
STATIC_KAKAO_CLIENT_ID = kakaoClientId;
STATIC_NAVER_CLIENT_ID = naverClientId;
STATIC_NAVER_CLIENT_SECRET = naverClientSecret;
STATIC_GOOGLE_CLIENT_ID = googleClientId;
STATIC_GOOGLE_CLIENT_SECRET = googleClientSecret;
}
// ✅ 정적 필드 Getter 메서드 추가
public static String getRedirectUrl() {
return STATIC_REDIRECT_URL;
}
public static String getKakaoClientId() {
return STATIC_KAKAO_CLIENT_ID;
}
public static String getNaverClientId() {
return STATIC_NAVER_CLIENT_ID;
}
public static String getNaverClientSecret() {
return STATIC_NAVER_CLIENT_SECRET;
}
public static String getGoogleClientId() {
return STATIC_GOOGLE_CLIENT_ID;
}
public static String getGoogleClientSecret() {
return STATIC_GOOGLE_CLIENT_SECRET;
}
}
staitc 필드들의 경우 Lombok의 Getter 메서드를 활용 할 수 없어 하나하나 넣어줬다.
그리고 상기의 redirectSocialLogin 메서드 호출하고 URL을 확인해보니 NULL이다.
흠 .. 왜일까 ?
private static final String REDIRECT_URI = OAuthConfig.getRedirectUrl();
- static의 경우 "클래스 로딩" 시점에 가져오고
@PostConstruct
public void init() {
STATIC_REDIRECT_URL = redirectUrl;
STATIC_KAKAO_CLIENT_ID = kakaoClientId;
STATIC_NAVER_CLIENT_ID = naverClientId;
STATIC_NAVER_CLIENT_SECRET = naverClientSecret;
STATIC_GOOGLE_CLIENT_ID = googleClientId;
STATIC_GOOGLE_CLIENT_SECRET = googleClientSecret;
}
- @PostConstruct의 경우 현재 클래스가 Bean으로 등록되고, 모든 의존성이 주입된 마지막에 실행된다.
- 따라서 맨처음 서버가 켜지고, JVM이 클래스를 메모리에 로드하는 시점이 더 우선적으로 작용됐기 떄문에 NULL로 찍힌것이다.
그럼 어떻게 해결하면될까?
- 간단하다
- @PostConstruct가 실행되고 나서 가져오면 되기때문에, static으로 받지않으면된다.
[기존] private static final String REDIRECT_URI = OAuthConfig.getRedirectUrl();
[변경] final String REDIRECT_URI = OAuthConfig.getRedirectUrl();
- 잘 나오는모습이다.
'SpringBoot' 카테고리의 다른 글
Hibernate Lazy Loading: 프록시 객체의 동작 원리와 실제 객체 조회 흐름 (0) | 2025.03.20 |
---|---|
JPA에서 ID 값이 NULL일 때와 존재할 때, INSERT vs UPDATE의 차이점 (0) | 2025.03.18 |
다양한 상황에서의 DB에 저장하는 시간을 알아보자 (0) | 2025.02.26 |
Redis에 엔티티 저장중 생긴 순환참조문제 (0) | 2025.01.23 |
JSP 란? (1) | 2025.01.21 |