https://console.cloud.google.com/apis/dashboard 접속
프로젝트 선택 > OAuth 동의 화면 > 외부 > 만들기
필수 항목 작성 > 범위 설정 > 테스트 사용자 등록 > 요약
Spring 공식 문서 참고:
https://docs.spring.io/spring-security/reference/servlet/oauth2/login/core.html
build.gradle에 dependency 추가
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
application.properties
spring.security.oauth2.client.registration.google.client-id=생성된 클라이언트 ID
spring.security.oauth2.client.registration.google.client-secret=클라이언트 보안 비밀번호
spring.security.oauth2.client.registration.google.scope=profile, email
패키지 > config > SecurityConfig.java
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private PrincipalOauth2UserService principalOauth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/user/**", "/bus/join").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/bus/**").hasRole("BUSINESS")
.and() // 일반 로그인 처리
.oauth2Login() // OAuth2 기반의 로그인 요청인 경우
.loginPage("/user/login") // 지정된 url로 이동
.userInfoEndpoint() // 로그인 성공후 사용자 정보를 가져옴
.userService(principalOauth2UserService); // 사용자 정보를 처리할 때 사용함
}
}
패키지 > oauth > PrincipalOAuth2UserService.java
@Service
public class PrincipalOAuth2UserService extends DefaultOAuth2UserService {
@Autowired
private UserRepository userRepository;
// userRequest는 code를 받아서 accessToken을 응답 받은 객체
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
// google의 회원 프로필 조회
OAuth2User oAuth2User = super.loadUser(userRequest);
// code를 통해 구성한 정보
System.out.println("userRequest clientRegistration : " + userRequest.getClientRegistration());
// token을 통해 응답받은 회원정보
System.out.println("oAuth2User : " + oAuth2User);
return processOAuth2User(userRequest, oAuth2User);
}
private OAuth2User processOAuth2User(OAuth2UserRequest userRequest, OAuth2User oAuth2User) {
OAuth2UserInfo oAuth2UserInfo = null;
if (userRequest.getClientRegistration().getRegistrationId().equals("google")) {
oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
}
// DB에서 해당 정보를 가진 구글 사용자가 있는지 확인
Optional<User> userOptional =
userRepository.findByProviderAndProviderId(oAuth2UserInfo.getProvider(), oAuth2UserInfo.getProviderId());
User user;
// 사용자가 이미 존재하는 경우
if (userOptional.isPresent()) {
user = userOptional.get();
user.updateEmail(oAuth2UserInfo.getEmail());
userRepository.save(user);
} else {
// 해당 정보를 가진 사용자가 없으면, DB에 해당 유저의 정보를 저장
user = User.builder()
.username(oAuth2UserInfo.getProvider() + "_" + oAuth2UserInfo.getProviderId())
.email(oAuth2UserInfo.getEmail())
.role(Role.SOCIAL)
.provider(oAuth2UserInfo.getProvider())
.providerId(oAuth2UserInfo.getProviderId())
.build();
userRepository.save(user);
}
return new PrincipalDetails(user, oAuth2User.getAttributes());
}
}
패키지 > config > auth > PrincipalDetails.java
OAuth2 User를 관리하기 위해서 기존에 있던 PrincipalDetails 클래스에서 OAuth2User도 implement 한다.
public class PrincipalDetails implements UserDetails, OAuth2User {
private static final long serialVersionUID = 1L;
private User user;
private Map<String, Object> attributes;
// 일반 시큐리티 로그인시 사용
public PrincipalDetails(User user) {
this.user = user;
}
// OAuth2.0 로그인시 사용
public PrincipalDetails(User user, Map<String, Object> attributes) {
this.user = user;
this.attributes = attributes;
}
public User getUser() {
return user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getEmail();
}
@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 Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(()->{ return user.getRoleKey();});
return authorities;
}
// 리소스 서버로 부터 받는 회원정보
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
// User의 Primary Key
@Override
public String getName() {
return user.getId() + "";
}
}