본 캠프_72일차

졸용·2025년 6월 10일

TIL

목록 보기
73/144

내가 구현하고자 하는 프로젝트의 구조:

  1. formLogin 없이 Google OAuth2 로그인만 통해 인증
  2. 로그인 성공 시, Google Access Token과 ID Token을 받아 옴.
    서버에서:
  3. Google Token을 검증하여 사용자가 진짜인지 확인
  4. 필요하면 회원가입 처리 (구글 계정 기반)
  5. 구글로부터 받은 사용자 정보를 활용해 서버에서 자체 JWT 발급 (Access Token + Refresh Token)
  6. 클라이언트는 이후 자체 JWT를 사용해 API 요청.
  7. 로그아웃 시 토큰 Redis 블랙리스트에 등록하여 처리.

내가 구현한 클래스:

  1. SecurityConfig
  2. JwtAuthenticationEntryPoint
  3. CustomOAuth2UserService
  4. OAuth2SuccessHandler
  5. OAuth2FailureHandler
  6. AuthService
  7. JwtProvider
  8. JwtFilter
  9. AuthController
  10. OAuth2LoginRequestDto, TokenReissueRequestDto, TokenResponseDto

클래스별 역할 요약 정리:


✅ 1. 전체 흐름 요약

OAuth2 로그인 + JWT 발급 구조는 아래와 같이 동작한다:

[1] 프론트엔드: 구글 로그인 버튼 클릭
   ↓
[2] 백엔드: Spring Security OAuth2 로그인 처리
   ↓
[3] OAuth2 로그인 성공 시, 사용자 정보 받아옴
   ↓
[4] 자체 서버에서 JWT(Access + Refresh) 발급
   ↓
[5] Access Token → 프론트로 응답
    Refresh Token → HttpOnly 쿠키로 저장
   ↓
[6] 이후 요청 시 Access Token으로 인증

상세 설명

[클라이언트]
  → /oauth2/authorization/google 요청  
↓
[Spring Security (OAuth2LoginFilter)]
  → Google OAuth2 인증 처리  
↓
[3. CustomOAuth2UserService]
  • Google에서 사용자 정보(email, name 등) 받아옴  
  • DB에 사용자 정보 저장 (없으면 신규 생성)  
  • DefaultOAuth2User 반환 (SecurityContext 등록용)  
↓
[4. OAuth2SuccessHandler]
  • CustomOAuth2UserService로부터 받은 User로 JWT 발급 (AuthService)  
  • AccessToken → 쿼리 파라미터로 프론트 전달  
  • RefreshToken → HttpOnly 쿠키로 저장 (7일)  
  • 클라이언트를 리다이렉트 (프론트에서 AccessToken 수신)  
↓
[5. OAuth2FailureHandler]
  • 인증 실패 시 401 에러 + JSON 응답 반환  
↓
[1. JwtFilter (SecurityConfig 등록)]
  • Authorization 헤더 또는 쿼리 파라미터에서 AccessToken 추출  
  • 블랙리스트/만료/위조 검증 → 유효성 검사  
  • SecurityContext에 Authentication 등록  
↓
[인증 완료 → 보호된 API 접근 가능]

✅ 2. 각 단계 상세 설명

📌 [1] 프론트엔드에서 OAuth2 로그인 요청

  • 프론트엔드는 구글 로그인 URL을 생성하고 사용자 브라우저를 해당 주소로 리디렉션한다.
  • URL 예: https://accounts.google.com/o/oauth2/auth?...

📌 [2] 백엔드에서 Spring Security가 OAuth2 로그인 처리

  • SecurityConfig에 등록된 /oauth2/authorization/google 엔드포인트가 작동.
  • 구글로부터 authorization code를 받아 Spring Security가 내부적으로 액세스 토큰을 요청하고 사용자 정보를 가져온다.

📌 [3] 사용자 정보 처리 (CustomOAuth2UserService)

  • 구글로부터 받은 사용자 정보를 활용해 자체 서비스의 사용자 정보와 연동한다.
  • 신규 사용자면 회원가입, 기존 사용자면 사용자 정보 업데이트 등.
  • 이때 OAuth2User에서 email, name, sub 같은 정보 추출한다.
public OAuth2User loadUser(OAuth2UserRequest userRequest) {
    OAuth2User oAuth2User = super.loadUser(userRequest);
    String email = oAuth2User.getAttribute("email");
    ...
}

📌 [4] JWT 발급 (OAuth2SuccessHandler)

  • OAuth2AuthenticationSuccessHandler 에서 AccessToken / RefreshToken을 발급한다.
  • OAuth2AuthenticationSuccessHandler 내부에서 AuthService.issueToken() 호출
  • AuthService 내부에서 JwtProvider.createAccessToken() 호출
  • Refresh Token은 Redis에 저장하고, 프론트엔드에는 HttpOnly 쿠키로 전달.

📌 [5] 응답

  • Access Token은 프론트엔드로 JSON 형태로 응답
  • Refresh Token은 쿠키로 브라우저에 저장 (프론트에서 접근 불가)
{
  "accessToken": "Bearer eyJhbGciOi..."
}

📌 [6] 인증 요청 시 AccessToken 사용 (JwtFilter 작동)

  • 클라이언트가 요청 시 Authorization: Bearer <AccessToken> 헤더를 전송
  • JwtFilter에서 토큰 파싱 및 검증 후 SecurityContext에 인증 객체 등록
String token = jwtProvider.resolveToken(request);
Claims claims = jwtProvider.getClaims(token);

✅ 보안 강화 포인트

항목설명
AccessToken15분 등 짧은 유효기간
RefreshToken7일 이상, Redis에 저장
쿠키RefreshToken은 HttpOnly + Secure
로그아웃Redis에서 RefreshToken 삭제 + 블랙리스트 등록 가능
재발급/auth/reissue 엔드포인트에서 RefreshToken으로 새로운 AccessToken 발급

✅ 그림 요약

1. [Client]        → /oauth2/authorization/google
2. [Spring Security] ← redirect from Google
3. [CustomOAuth2UserService] → 사용자 정보 처리
4. [JwtProvider]     → JWT 발급 (Access + Refresh)
5. [Redis]           → RefreshToken 저장
6. [Http Response]   → AccessToken (JSON), RefreshToken (HttpOnly Cookie)
7. [Client 요청]     → Authorization: Bearer <AccessToken>
8. [JwtFilter]       → 검증 후 SecurityContext 등록

✅ 관련 클래스 요약

클래스역할
SecurityConfigOAuth2 설정, 필터 등록
CustomOAuth2UserServiceOAuth2 사용자 정보 매핑
OAuth2SuccessHandler로그인 성공 시 JWT 발급 및 쿠키 저장
JwtProviderJWT 생성/파싱/검증
JwtFilter요청 시 토큰 인증 처리
AuthController토큰 재발급 및 로그아웃 처리
RedisTemplateRefreshToken 저장소
profile
꾸준한 공부만이 답이다

1개의 댓글

comment-user-thumbnail
2025년 7월 9일

이걸 구상하시고 벌써 한달이 지나서 프로젝트가 잘 마무리가 되었네요.
잘 구현해내 주셔서 감사합니다. 고생많으셨어요!

답글 달기