본문으로 바로가기

1. 구글 로그인 API 토큰 발급

https://cloud.google.com/?hl=ko 

 

https://cloud.google.com/?hl=ko

 

cloud.google.com

 

새 프로젝트 생성

 

 

프로젝트 생성 후 왼쪽 메뉴에서 OAuth 동의 화면 클릭

 

 

외부 선택 후 만들기

 

앱 등록정보에서 필수 입력값만 입력 후 다음

 

 

 

범위 추가 또는 삭제 선택 후 위 3개 (email, profile, openid만 선택)

 

 

 

사용자 인증 정보 선택 후 사용할 url 입력하기 

 

 

 

 

 

모든 과정을 완료했으면 클라이언트 ID 및 secret key를 발급받을 수 있다. 

 

 

2. SpringBoot에 Google 로그인 API 연동

 

먼저 oauth 사용을 위한 설정 파일을 생성합니다. 

!주의 github에 프로젝트를 관리한다면 이런 secret key가 포함된 파일은 ignore 해주어야 합니다. (private은 상관없음)

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: 발급받은 ID
            client-secret: 발급받은 key
            scope: profile,email

 

그리고 기존에 있던 application.yml 파일에 

spring.profiles.include: oauth를 추가해 줍니다. 

 

gradle 설정

    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'

 

 

Config파일 설정

config파일에서 url에 따른 권한 설정이나 로그아웃 후 처리, 로그인 처리 등을 설정할 수 있습니다. 

 

예전에는 WebSecurityConfigurerAdapter를 상속받아서 configure 메소드를 오버라이딩 하여 사용했지만 현재는 deprecated 되었고 filterChain 사용을 권장하고 있습니다. 

@RequiredArgsConstructor
@EnableWebSecurity  // spring security 설정 활성화
public class SecurityConfig {
    private final CustomOAuth2UserService customOAuth2UserService;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.csrf().disable().headers().frameOptions().disable() // h2-console을 사용하기 위해 옵션 disable
                .and()
                    .authorizeRequests().antMatchers("/", "/css/**", "/images/**", "/js/**", "/h2-console/**").permitAll()
                    .antMatchers("/api/v1/**").hasRole(Role.USER.name())    // 권한 관리 대상, USER 권한을 갖는 사람만 가능하도록
                    .anyRequest().authenticated()   // 나머지 URL은 로그인한 사용자들에게 허용
                .and()
                    .logout()
                        .logoutSuccessUrl("/")
                .and()
                    .oauth2Login()
                        .userInfoEndpoint()
                            .userService(customOAuth2UserService).and().and().build();  // 로그인 성공 후 후속조치
    }

}

 

 

그 다음 구글 로그인 API 를 통해 받은 유저를 등록할 Entity를 생성합니다. 

@Getter
@NoArgsConstructor
@Entity
public class Member extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String email;

    @Column
    private String picture;

    @Enumerated(EnumType.STRING) // Enum 값을 어떤 형태로 정할지 결정, default = int
    @Column(nullable = false)
    private Role role;

    @Builder
    public Member(String name, String email, String picture, Role role) {
        this.name = name;
        this.email = email;
        this.picture = picture;
        this.role = role;
    }

    public Member update(String name, String picture) {
        this.name = name;
        this.picture = picture;

        return this;
    }

    public String getRoleKey() {
        return this.role.getKey();
    }
}

 

 

OAuth2UserService 생성

OAuth2를 사용해 로그인 후 user 정보를 세팅하는 클래스를 생성합니다. 

 

@RequiredArgsConstructor
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
    private final UserRepository userRepository;
    private final HttpSession httpSession;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2UserService<OAuth2UserRequest, OAuth2User> delegate = new DefaultOAuth2UserService();

        OAuth2User oAuth2User = delegate.loadUser(userRequest);

        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails()
                .getUserInfoEndpoint().getUserNameAttributeName();

        OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());

        Member member = saveOrUpdate(attributes);

        httpSession.setAttribute("user", new SessionUser(member));    // 세션에 저장

        return new DefaultOAuth2User(Collections.singleton(new SimpleGrantedAuthority(member.getRoleKey())), attributes.getAttributes(), attributes.getNameAttributeKey());
    }

    private Member saveOrUpdate(OAuthAttributes attributes) {
        Member member = userRepository.findByEmail(attributes.getEmail())
                .map(entity -> entity.update(attributes.getName(), attributes.getPicture()))
                .orElse(attributes.toEntity());

        return userRepository.save(member);
    }
}