1. 코드받기 (인증)
2. 엑세스 토큰받기
3. 사용자 프로필 정보 가져오기
4. 정보를 통해서 회원가입
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 객체가 생성되는것이다.
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;
}
}
@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);
}