CustomOAuth2User

google이나 naver에서 받아온 정보를 담고 있는 기본 OAuth2User 안에는 email, name, profile_image같은 정보만 들어있다.

그런데 사용자가 로그인을 성공한 직후, 서비스는 SuccessHandler에서 전용 AccessToken과 RefreshToken을 만들어서 브라우저로 내려주어야 한다. (그래야지만, 이후에 요청이 왔을 경우, 이 AccessToken으로 내 회원인지 판단을 할 수 있기 때문)

이때 AccessToken의 Payload에는 다음과 같은 정보가 들어간다.

여기서 문제는 super.loadUser(userRequest)로 받아온 회원 정보(OAuth2User)를 그냥 리턴해버리면 내가 생성한 member_id나 Role 정보가 존재하지 않는다.

따라서 CustomOAuth2MemberService의 마지막 부분에서, 방금 DB에 저장한 Member객체로부터 id와 Role을 뽑아낸 뒤, 이름 담을 수 있는 바구니(CustomOAuth2User)를 만들어서 핸들러로 넘겨주는 것이다.

코드의 흐름

  1. CustomOAuth2MemberService: 구글에서 온 로그인이 성공했네. DB에 저장하니까 이 회원 PK는 5번이고 권한은 USER야. 이 정보를 CustomOAuth2User 객체에 담아서 리턴할게.
  2. OAuth2LoginSuccessHandler: CustomOAuth2MemberService에서 넘겨준 객체를 받아보니 CustomOAuth2User네? 여기서 .getPrincipal()을 통해 PK 5번이랑 USER 정보만 빼서 AccessToken로 브라우저한테 줘야겠다.

전체 흐름 정리

소셜 로그인 성공
       ↓
CustomOAuth2MemberService.loadUser()
  → DB 저장/조회
  → CustomOAuth2User 반환 (memberId, email, role 포함)
       ↓
OAuth2LoginSuccessHandler.onAuthenticationSuccess()
  → CustomOAuth2User에서 정보 추출
  → AccessToken 생성  →  Body로 클라이언트 전달 (메모리 저장)
  → RefreshToken 생성 →  HttpOnly 쿠키로 전달 + DB 저장
       ↓
이후 API 요청
  → 클라이언트가 Header에 "Authorization: Bearer {accessToken}" 첨부
  → JwtFilter가 토큰 파싱 → payload로 회원 식별 (DB 조회 없음)
       ↓
AccessToken 만료 시
  → 쿠키의 RefreshToken으로 재발급 요청
  → DB의 RefreshToken과 비교 검증 후 AccessToken 재발급

구현 코드 예시

CustomOAuth2User - SuccessHandler가 JWT를 생성하기 위해 (id, Role) 정보를 여기서 꺼낸다.

@Getter
@RequiredArgsConstructor
public class CustomOAuth2User implements OAuth2User {

    private final Long userId;
    private final Role role;
    private final String nickName;

    @Override
    public String getName() {
        return nickName;
    }

    @Override
    public Map<String, Object> getAttributes() {
        return null;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        Collection<GrantedAuthority> collection = new ArrayList<>();
        collection.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return "ROLE_" + role.name();
            }
        });
        return collection;
    }
}

OAuth2SuccessHandler