Spring Security 구글 회원정보 후처리

바그다드·2023년 4월 8일
0

Spring Security

목록 보기
8/17

구글 로그인 진행 방식

  • 구글 로그인 버튼 클릭 -> 구글 로그인 창 -> 로그인을 완료 -> code를 리턴(Oauth-client라이브러리 -> AccessToken 요청 = userRequest정보가 생성 -> loadUser함수 호출 -> 구글로부터 회원 프로필을 받아준다.
  • loadUser함수가 구글 프로필을 받아주는 역할을 한다.
  • 그럼 유저 정보를 받아오는 방법을 알아보자

Authentiacation객체가 가질 수 있는 2가지 타입

  • 앞서 스프링 시큐리티를 통해 생성된 세션은 별도의 공간에서 관리되고, 여기에 접근하기 위해서는 Authentication객체를 활용해야 한다고 하였다.
  • 위의 그림을 보자 로그인 방식에 따라 Authentication에는 UserDetails가 들어갈 수도, OAuth2User객체가 들어갈 수도 있다.
  • 그럼 일단 각 객체에 따라 유저 정보를 가져오는 방법을 알아보자.

1. UserDetails

  • 여기서 User 정보를 얻을 수 있는 방법은 2가지가 있는데
  1. Authentication을 PrincipalDetails로 캐스팅하여 가져오는 방법
  2. @AuthenticationPrincipal을 사용하여 user정보를 가져오는 방법이다.

PrincipalOauth2UserService 코드 추가

PrincipalOauth2UserService의 loadUser메서드에 아래 코드를 추가해주자

OAuth2User oAuth2User = super.loadUser(userRequest);

Index Controller 코드 추가

  • index controller에 아래 코드를 추가하자
@GetMapping("/test/login")
    public @ResponseBody String loginTest(Authentication authentication,
    @AuthenticationPrincipal PrincipalDetails userDetails) { // DI(의존성주입)
        System.out.println("/test/login =========");
        // 1. Authetication을 PrincipalDetails로 캐스팅하여 사용하는 방법
        // PrincipalDetails는 우리가 앞서 생성했던 config.auth.PrincipalDetails
        PrincipalDetails principalDetails = (PrincipalDetails) authentication.getPrincipal();
        System.out.println("principalDetails = " + principalDetails.getUser());

        // 2. @AuthenticationPrincipal을 사용하는 방법
        // PrincipalDetails가 UserDetails를 상속받고 있기 때문에 
        // UserDetails 대신에 PrincipalDetails를 사용할 수 있음
        System.out.println("userDetails = " + userDetails.getUser());
        return "세션 정보 확인하기";
    }
  • 이때 @AuthenticationPrincipal에 UserDetails를 사용해야 하지만, PrincipalDetails가 UserDetails를 상속받고 있기 때문에 UserDetails 대신에 PrincipalDetails를 사용할 수 있다
  • 이러한 방법으로 일반 로그인을 한 유저의 정보를 가져올 수 있다.
/test/login =========
principalDetails = User(id=4, username=test,
password=$2a$10$BoYddAVEZUr6OWm2ttODaOdMykaawnD4zW11RLbSCQvZ6b8Yh7bJu,
email=test@naver.com, role=ROLE_USER, provider=null, providerId=null,
loginDate=null, createDate=2023-04-03 15:37:02.575)

userDetails = User(id=4, username=test,
password=$2a$10$BoYddAVEZUr6OWm2ttODaOdMykaawnD4zW11RLbSCQvZ6b8Yh7bJu,
email=test@naver.com, role=ROLE_USER, provider=null, providerId=null, 
loginDate=null, createDate=2023-04-03 15:37:02.575)
  • 하지만 구글 로그인을 하고 해당 페이지로 접근해보면 캐스팅 에러가 발생한다.

2. OAuth2를 이용해 user데이터 가져오기

IndexController에 추가

  • 얘도 Authentication을 OAuth2User로 캐스팅 해서 유저 정보를 가져오는 방법과 @AuthenticationPrincipal을 이용해 OAuth2User를 가져와 유저 정보를 가져오는 방법이 있다.
 @GetMapping("/test/oauth/login")
    public String loginOAuthTest(Authentication authentication,
    @AuthenticationPrincipal OAuth2User oAuth) { // DI(의존성주입)
        System.out.println("/test/oauth/login =========");
        // 1. 캐스팅해서 가져오기
        OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
        System.out.println("authentication = " + oAuth2User.getAttributes());
        // 2. @AuthenticationPrincipal로 가져오기
        System.out.println("OAuth2User = " + oAuth.getAttributes());
        return "OAuth 세션 정보 확인하기";
    }

UserDetails와 OAuth2User의 user정보는 앞서 정의한 loadUser로부터 가지고 온다.

//com.cos.security1.config.oauth.PrincipalOauth2UserService
@Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        // registrationId로 어떤 oauth로 로그인 했는지 알 수 있음
        System.out.println("userRequest : " + userRequest.getClientRegistration());
        System.out.println("userRequest = " + userRequest.getAccessToken().getTokenValue());
        // 구글 로그인 버튼 클릭 -> 구글 로그인 창 -> 로그인을 완료 
        // -> code를 리턴(Oauth-client라이브러리 -> AccessToken 요청
        // userRequest정보 -> loadUser함수 호출 -> 구글로부터 회원 프로필을 받아줌
        System.out.println("userRequest = " + super.loadUser(userRequest).getAttributes());

        OAuth2User oAuth2User = super.loadUser(userRequest);
        // 회원가입을 강제로 진행해볼 예점
        return super.loadUser(userRequest);
    }
  • 그런데 일반 로그인할 때와 OAuth2를 이용한 로그인을 하는 방식에 따라 컨트롤러에서 받는 매개변수가 달라진다는 문제가 있다.
  • 위의 그림을 보자 로그인 방식에 따라 Authentication에는 UserDetails가 들어갈 수도, OAuth2User객체가 들어갈 수도 있다.
    그럼 컨트롤러에서 매개변수를 받을 때 UserDetails를 받아서 처리해야할지, OAuth2User객체를 받아서 처리해야하는지에 대한 문제가 발생한다.
  • 그렇다면 해결 방법은 UserDetails와 OAuth2User를 상속받는 객체를 새로 만들어 이를 Authentication에 담아주면 된다.
  • 앞서 UserDetails는 Authentication이 생성될 때 매개변수로 Authentication(UserDetails)
    이러한 형태로 들어간다. 아래의 코드를 보자
  • loadUserByUsername 메서드를 통해 Authentication에 PrincipalDetails가 매개변수로 들어간다.
    - 여기서 PrincipalDetails는 UserDetails를 상속 받고 있다
  • 그럼 PrincipalDetails가 이미 UserDetails를 상속 받고 있으므로, OAuth2User도 함께 상속 받는다면 컨트롤러에 PrincipalDetails를 매개변수로 받아 일반 로그인과 OAuth로그인 둘 다 처리할 수 있게 된다.
  • 이렇게 하면 OAuth2User를 상속 받고 있기 때문에 이제 상속 메서드를 구현해주면 된다.
profile
꾸준히 하자!

0개의 댓글