[Spring Security] 6. OAuth2 Google Login ②

개발자·2022년 5월 11일
0

Spring Security

목록 보기
6/11
post-thumbnail

Google Login 후처리

1. 코드받기 (인증)

  • 구글에 정상적으로 로그인했다고 인증이 되었다.

2. 엑세스 토큰받기

  • 사용자 정보에 접근할 권한이 생긴다.

3. 사용자 프로필 정보 가져오기

4. 정보를 통해서 회원가입

  • 추가정보가 필요할 시에는 받아야 한다.

OAuth2UserService

  • UserInfo 엔드포인트에서 최종 사용자의 속성을 가져오며 OAuth2User타입의 AuthenticatedPrincipal을 리턴하는 DefaultOAuth2UserService를 구현한 클래스이다.

  • loadUser 메소드를 오버라이드 한다.

  • loadUser 메소드는 구글로 부터 받은 userRequest 데이터에 대한 후처리되는 함수이다.

  • 구글 로그인 버튼 -> 구글로그인창 -> 로그인을 완료 -> code를 리턴(OAuth-Client라이브러리) -> AccessToken요청

  • userRequest 정보 -> loadUser 함수 호출 -> 구글로부터 회원프로필을 받아준다.

@Service
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oauth2User = super.loadUser(userRequest);
        System.out.println("getAttributes : " + oauth2User.getAttributes());

        String provider = userRequest.getClientRegistration().getRegistrationId(); // Google
        String providerId = oauth2User.getAttribute("sub"); // Google ProviderId Sub
        String username = provider+"_"+providerId; // google_1231241512831
        String password = "1234"; // 크게 의미 없음.
        String email = oauth2User.getAttribute("email");
        String role = "ROLE_USER";

        User userEntity = userRepository.findByUsername(username);

        if(userEntity == null){
            userEntity = User.builder()
                    .username(username)
                    .password(password)
                    .email(email)
                    .role(role)
                    .provider(provider)
                    .providerId(providerId)
                    .build();
            userRepository.save(userEntity);
        }

        return new PrincipalDetails(userEntity, oauth2User.getAttributes());
    }
}
  • 다음과 같이 코드를 구성하였다.

  • oauth2User는 attributes라는 속성을 가지고있다.

  • attributes에는 본인에 구글 아이디에 대한 개인정보를 담고 있다.

  • 그 정보를 이용하여 User Entity를 생성하고 회원가입을 진행하는 것이다.

  • 다음을 통해 @Authentication Principal 객체가 생성되는것이다.


PrincipalDetails

public class PrincipalDetails implements UserDetails, OAuth2User {

    private User user; // 컴포지션
    private Map<String,Object> attributes;

    // 일반 로그인 생성자
    public PrincipalDetails(User user){
        this.user = user;
    }

    // OAuth 로그인 생성자
    public PrincipalDetails(User user,Map<String,Object> attributes){
        this.user = user;
        this.attributes = attributes;
    }

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

    // 해당 User의 권한을 리턴하는곳.
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collect = new ArrayList<>();
        collect.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collect;
    }


    // User 의 password 리턴
    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public String getName() {
        return null;
    }
}
  • 일반 로그인 사용자와 OAuth2 로그인 사용자 모두 Principal 객체로 받기위해서 OAuth2User를 상속받고 생성자를 추가한다.

SecurityConfig

@Autowired
private PrincipalOauth2UserService principalOauth2UserService;
http.authorizeRequests()
             .antMatchers("/user/**").authenticated()
             .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
             .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
             .anyRequest().permitAll()
             .and()
             .formLogin()
             .loginPage("/loginForm")
             .loginProcessingUrl("/login")
             .defaultSuccessUrl("/")
             .and()
             .oauth2Login()
             .loginPage("/loginForm")
             .userInfoEndpoint()
             .userService(principalOauth2UserService);
    }
  • OAuth2 로그인을 위해 다음과 같은 코드를 추가한다.

0개의 댓글