OAuth에 관한 설명 ~~
구글APIs
위 링크로 접근후
1

2

3

4

5

6

7

/login/oauth2/code는 고정
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</arti
<version>3.0.2</version>
</dependency>

spring:
security:
oauth2:
client:
registration:
google:
client-id: {클라이언트 ID}
client-secret: {클라이언트 보안 비밀번호}
scope:
- email
- profile
.oauth2Login(form->form
.loginPage("/login")
.userInfoEndpoint()
.userService(principalOauth2UserService)
);
이때 principalOauth2UserService에서 loadUser 메소드를 실행시킨다
Spring Securiy는 Authentication라는 세션정보를 지니고 있다
이때 일반 User는 UserDetails를, OAuth User는 OAuth2User를 반환한다
UserDetailsService를 상속받은 클래스에서 loadUserByUsername(String usernaame) 이실행되며, 이 메소드에서 UserDetails를 리턴한다
PrincipalDetailsService
@Service
@Log4j2
public class PrincipalDetailsService implements UserDetailsService{
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
log.info("loadUserByUsername : "+usernmae);
User user = userRepository.findByUsername(username);
log.info(user);
return user;
}
}
DefaultOAuth2UserService를 상속받은 클래스에서 loadUser(OAuth2UserRequest userRequest)이 실행되며, 이 메소드에서 OAuth2User가 리턴된다
@Service
@Log4j2
public class PrincipalOauth2UserService extends DefaultOAuth2UserService {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserRepository userRepository;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest)
throws OAuth2AuthenticationException {
log.info("loadUser : "+userRequest);
OAuth2User oAuth2User = super.loadUser(userRequest);
log.info(oAuth2User.getAttributes());
return oAuth2User ;
}
}
이때, 접속한 User가 일반 User냐, OAuth User냐에 따라 별도의 작업을 수행하게 된다.
이를 위해 Authentication에 주입 가능한, UserDetails와 OAuth2User를 둘 다 상속받은 별도의 객체를 생성하여 전달해주었다
이전에 사용한 PrincipalDetails를 사용해보자
PrincipalDetails
@Data
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 Collection<? extends GrantedAuthority> getAuthorities() {
// User의 권한을 리턴
Collection<GrantedAuthority> collect = new ArrayList<>();
collect.add(new GrantedAuthority() {
@Override
public String getAuthority(){
return user.getRole();
}
});
return collect;
}
@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 Map<String, Object> getAttributes() {
return attributes;
}
@Override
public String getName() {
return null;
}
}
두 인터페이스를 상속받은 해당 메소드는 이제 Authentication에 주입이 가능해진다
이를 위해 loadUserByUsername및 loadUser 메소드에서 PrincipalDetails를 리턴하였다
return user;
=> return new PrincipalDetails(user);
return oAuth2User;
=> return new PrincipalDetails(user,oAuth2User.getAttributes());