🔥 1. OAuth2 인증 시 네이버와 구글의 DefaultOidcUser 차이로 인한 문제
🛑 문제 상황
- 네이버와 구글에서 받아오는 OAuth2 유저 객체가 다름.
- 구글은 OIDC 기반이라 DefaultOidcUser를 반환하지만, 네이버는 OIDC 지원이 없어 DefaultOAuth2User를 반환함.
- CustomOAuth2UserService에서 DefaultOidcUser로 캐스팅 시 예외 발생.
💡 해결 방법
- OAuth2User 인터페이스를 기준으로 핸들링하는 팩토리 패턴을 적용.
- OAuth2UserFactory를 만들어 제공자별 OAuth2Attribute 변환.
✅ OAuth2UserFactory 구현
@Component
@RequiredArgsConstructor
@Slf4j
public class OAuth2UserFactory {
public OAuth2Attribute getOAuth2UserInfo(Authentication authentication) {
if (authentication.getPrincipal() instanceof DefaultOidcUser) {
return extractGoogleUserInfo((DefaultOidcUser) authentication.getPrincipal());
} else if (authentication.getPrincipal() instanceof DefaultOAuth2User) {
return extractGoogleUserInfo((DefaultOAuth2User) authentication.getPrincipal());
} else if (authentication.getPrincipal() instanceof CustomOAuth2User) {
return extractNaverUserInfo((CustomOAuth2User) authentication.getPrincipal());
}
log.error("Unexpected principal type: {}", authentication.getPrincipal().getClass().getName());
throw new OAuth2AuthenticationException("Unsupported OAuth2 provider");
}
private OAuth2Attribute extractGoogleUserInfo(DefaultOAuth2User oauth2User) {
Map<String, Object> attributes = oauth2User.getAttributes();
return OAuth2Attribute.builder()
.providerId((String) attributes.get("sub"))
.email((String) attributes.get("email"))
.nickname((String) attributes.get("name"))
.provider("google")
.build();
}
private OAuth2Attribute extractNaverUserInfo(CustomOAuth2User oAuth2User) {
Map<String, Object> attributes = oAuth2User.getAttributes();
Map<String, Object> response = (Map<String, Object>) attributes.get("response");
return OAuth2Attribute.builder()
.providerId((String) response.get("id"))
.email((String) response.get("email"))
.nickname((String) response.get("name"))
.provider("naver")
.build();
}
}
🔥 2. JWT 필터에서 SecurityContextHolder 인증 정보가 설정되지 않는 문제
🛑 문제 상황
- SecurityContextHolder.getContext().setAuthentication(authenticationToken); 호출 후에도 보안 컨텍스트가 설정되지 않음.
- 인증되지 않은 요청으로 처리됨.
💡 해결 방법
- doFilterInternal() 내부에서 SecurityContextHolder 설정 후 필터 체인 실행 확인.
- UsernamePasswordAuthenticationToken 설정 시 setAuthenticated(true) 필요할 수도 있음.
✅ JWT 인증 필터 수정
if (jwtService.validateToken(token)) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
authenticationToken.setAuthenticated(true); // ✅ 인증 설정 추가
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
🔥 3. OAuth2 인증 성공 후 Redirect 시 Header에 토큰이 포함되지 않는 문제
🛑 문제 상황
- onAuthenticationSuccess 핸들러에서 response.sendRedirect(url); 호출 후 헤더에 토큰이 없음.
- 리디렉션이 여러 번 발생하여 헤더에 토큰을 담아 전송하기 어려움.
💡 해결 방법
- 쿠키를 이용하여 JWT 저장.
- CORS 정책에서 allowCredentials(true) 설정 필요.
✅ OAuth2AuthenticationSuccessHandler 수정
jwtUtil.addTokenInCookie(response, "Authorization", tokens[0], 60 * 60);
jwtUtil.addTokenInCookie(response, "Refresh-Token", tokens[1], 60 * 60 * 24 * 7);
String redirectUrl = baseUrl + "/auth/callback";
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
📌 Security & JWT 구현과정 트러블 슈팅 정리
- OAuth2 인증 문제 해결: OAuth2UserFactory를 사용해 제공자별 유저 정보를 추출하도록 수정.
- JWT 인증 필터 문제 해결: SecurityContextHolder 설정 후 setAuthenticated(true) 추가.
- OAuth2 Redirect 문제 해결: 헤더가 아닌 쿠키를 이용해 JWT 저장.
'JAVA > Spring Security' 카테고리의 다른 글
Spring Security (스프링 시큐리티) Ch.1 (0) | 2023.03.15 |
---|
댓글