(2024모각소)DefaultOAuth2UserService 인터페이스

LEEHYUNJE·2024년 8월 13일
0

아주대학교_모각소!

목록 보기
18/23

처음 활용할때 인터페이스 명이 너무 길고 어떤 역할을 할 때 써야하는지 잘 알지 못했는데, 오늘 기회가 생겨 정리하게 되었다.

DefaultOAuth2UserService 개요

위 인터페이스는 OAuth 2.0 로그인 프로세스 중에 OAuth 2.0 또는 OpenID Connect(OIDC) 제공자(Google, Facebook 등)로부터 사용자 정보 검색 및 처리를 담당하는 Sprint Security에서 제공하는 클래스이다.

사용자가 OAuth 2.0 공급자를 사용하여 인증을 시도하면 Spring Security가 자동으로 OAuth 2.0 인증 흐름을 처리한다. 이 프로세스의 핵심 구성 요소 중 하나는 사용자가 인증된 후 OAuth 2.0 공급자로부터 사용자 프로필 정보를 가져오는 'DefaultOAuth2UserService'이다.

OAuth 2.0 흐름에서 역할

1. OAuth 공급자로 리디렉션된 사용자

: 사용자가 Google(또는 다른 OAuth 공급자)로 로그인하기로 선택하면 Sprint Security는 사용자를 공급자의 인증 끝점으로 리디렉션한다.

2. 사용자가 권한 부여

: 사용자는 Google에 로그인하고 자신의 프로필 정보에 액세스 할 수 있는 권한을 애플리케이션에 부여

3. 인증 코드 반환

: 권한이 부여되면 Google은 승인 코드를 사용하여 사용자를 애플리케이션에 지정된 리디렉션 URI로 다시 리디렉션

4. 액세스 토큰 교환 인증코드

: Spring Security는 OAuth2LoginAuthenticationFilter 를 사용하여 OAuth 공급자의 토큰 엔드 포인트에 요청하여 액세스 토큰에 대한 인증 코드 교환을 자동으로 처리

5. 사용자 정보 가져오기

: 액세스 토큰을 얻으면 DefaultOAuth2UserService가 호출된다. 이메일, 프로필사진, 이름 등과 같은 인증된 사용자의 세부 정보를 검색하기 위해 액세스 토큰을 사용하여 OAuth 공급자의 사용자 정보 엔드포인트에 요청

6 'OAuth2User' 객체 생성

: DefaultOAuth2UserService는 공급자의 응답을 처리하고 사용자 정보를 추출한 후 이를 OAuth2User 객체에 래핑합니다. 그런 다음 이 객체는 Spring Security에서 인증된 주체를 생성하는 데 사용

7. 사용자 인증

: 'OAuth2User' 개체는 'SecurityContext'에 저장되며 사용자는 인증된 것으로 간주도니다. 애플리케이션은 이 정보를 사용하여 사용자 세션을 관리하거나 데이터베이스에 저장할 수 있다.

Controller로 관여를 하지 않은 이유

처음 OAuth 2.0을 예시 코드를 따라치며 생각했던 궁금증이 있었다.

"왜 컨트롤러로 URL 매핑설정을 하지 않았는데 어떻게 돌아가는거지?"

이것에 스스로에 대한 답변을 다뤄보겠다.

Sprint Security가 흐름을 처리한다.

: Sprint Security의 필터(OAuth2LoginAuthenticationFilter, DefaultOAuth2UserService 등)은 공급자(Authorization Server)로의 리디렉션, 토큰용 코드 교환, 사용자 정보 가져오기에 이르기짜기 전체 OAuth 흐름을 관리한다.

자동 구성

: OAuth 2.0 로그인을 위해 Sprint Security를 구성하면 사용자 정의 컨트롤러 코드를 작성할 필요 없이 로그인 프로세스를 처리하는 데 필요한 엔드포인터와 필터가 자동으로 설정된다.

보안 필터

: OAuth 2.0 로그인 흐름은 컨트롤러가 아닌 보안 필터에 의해 시작되고 처리된다. 이러한 필터는 요청을 가로채고 OAuth 2.0을 사용하여 사용자를 인증해야 하는지 결정한다. 인증 해야한다면, OAuth 공급자로 리디렉션하고 후속 통신을 처리한다.

콜백 처리

: 사용자가 권한을 부여한 후 OAuth 공급자는 컨트롤러가 아닌 Sprint Security에서 관리하는 콜백 URL로 사용자를 다시 리디렉션한다. 다음, Spring Security는 OAuth 공급자와 상호작용하고, 사용자에 대한 인증된 세션을 생성하여 인증프로세스를 완료한다.

컨트롤러 개입없이 프로세스 요약

  1. 사용자가 보안 리소스에 액세스하려고 합니다 → Spring Security는 인증을 위해 사용자를 Google로 리디렉션합니다.

  2. 사용자를 인증하고 권한을 부여합니다 → Google은 인증 코드를 사용하여 사용자를 애플리케이션으로 다시 리디렉션합니다.

  3. Spring Security는 코드를 액세스 토큰으로 교환합니다 → DefaultOAuth2UserService는 액세스 토큰을 사용하여 Google에서 사용자 정보를 검색합니다.

  4. 사용자가 인증되었습니다 → Spring Security가 인증된 사용자 세션 생성을 처리합니다.

코드 예시

@Service
@RequiredArgsConstructor
@Slf4j
public class CustomOauth2UserService extends DefaultOAuth2UserService {

    private final MemberRepository memberRepository;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        //super.loadUser(userRequest): 이는 Google과 같은 OAuth2 제공자로부터 사용자 세부정보를 로드하는 기본 구현을 호출합니다. 반환된 OAuth2User에는 사용자의 속성이 포함됩니다.
        OAuth2User oAuth2User = super.loadUser(userRequest);
        // 유져의요청을 받은 attirubutes를 로그로 찍어본다.


        // 공급자 id 식별 ex) google
        String provider = userRequest.getClientRegistration().getRegistrationId();

        OAuth2UserInfo oAuth2UserInfo = null;

        // 뒤에 진행할 다른 소셜 서비스 로그인을 위해 구분 => 구글
        if(provider.equals("google")){
            log.info("구글 로그인");
            // oAuth2UserInfo 인터페이스를 구현하는 구글유져 디테일의 attributes를 받는다.
            oAuth2UserInfo = new GoogleUserDetails(oAuth2User.getAttributes());

        }else if (provider.equals("kakao")) {
            log.info("카카오 로그인");
            oAuth2UserInfo = new KakaoUserDetails(oAuth2User.getAttributes());
        }else if (provider.equals("naver")) {
            log.info("네이버 로그인");
            oAuth2UserInfo = new NaverUserDetails(oAuth2User.getAttributes());
        }

        String providerId = oAuth2UserInfo.getProviderId();
        String email = oAuth2UserInfo.getEmail();
        String loginId =  provider + "_" + providerId;
        String name = oAuth2UserInfo.getName();


        Member findMember = memberRepository.findByLoginId(loginId);
        Member member;

        log.info("getAttributes : {}",oAuth2User.getAttributes());
        // 존재하지 않다면 바로 회원가입
        if (findMember == null) {
            member = Member.builder()
                    .loginId(loginId)
                    .name(name)
                    .provider(provider)
                    .providerId(providerId)
                    .role(MemberRole.USER)
                    .build();
            log.info("Saving member: {}", member);
            memberRepository.save(member);
        } else{
            // 존재한다면, 찾아서 member에 저장
            member = findMember;
        }

        return new CustomOauth2UserDetails(member, oAuth2User.getAttributes());
    }

loadUser 메소드
:이 메소드는 OAuth 2.0 인증이 성공한 후, OAuth 2.0 제공자로부터 사용자 정보를 가져오고 이를 처리하는 메소드이다.
super.loadUser(userRequest)를 호출하여 기본적인 사용자 정보 로딩을 수행합니다. 이 호출로 OAuth2User 객체를 얻을 수 있습니다.

CustomOauth2UserDetails 객체 반환
:CustomOauth2UserDetails 객체를 반환한다. 이 객체는 Spring Security의 SecurityContext에 저장되어 애플리케이션에서 사용자 정보를 참조할 수 있게 된다.


모각소 후기

이 더운날 모두가 각자 소프트웨어하는 시간을 가졌다. 오늘은 Sprint Security의 정수 DefaultOAuth2UserService를 사용해서 어떻게 어플리케이션 입장에서 정의한 컨트롤러 없이 OAuth 2.0 과정이 돌아가게되는지 공부해 봤다. 이제 로그인 관련해서는 JWT 나 access Token 발급에 대해 과정이 남아있지만, 먼저 상품 관련한 기능을 만들고 고객의 장바구니를 구분지을 때 다시 생각해보도록 하자. 오늘도 고생했따

profile
현재진행중

0개의 댓글