OAuth2(3) OAuth2 Client 라이브러리 사용 카카오 로그인

2022. 1. 20. 10:51·Programming/Spring

application-oauth.yml

spring:
  security:
    oauth2:
      client:
        registration:
          kakao:
            client-id: "Kakao Developers에서 받은 client-id "
            client-secret: "Kakao Developers에서 받은 client-secret"
            redirect-uri: "Kakao Developers에서 지정한 redirect-uri "
            authorization-grant-type: authorization_code
            client-authentication-method: POST
            client-name: Kakao

CustomOAuth2UserService

DefaultOAuth2UserService을 상속 받은 커스텀 클래스.  loadUser라는 메소드에 의해 후처리가 일어난다. userRequest에는 프로필 정보가 들어있다.

@Service
@Slf4j
@RequiredArgsConstructor
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
    private final AccountRepository accountRepository;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {

        OAuth2User oAuth2User = super.loadUser(userRequest);

        return processOAuth2User(userRequest, oAuth2User);
    }

    private OAuth2User processOAuth2User(OAuth2UserRequest userRequest, OAuth2User oAuth2User) {

        OAuth2UserInfo oAuth2UserInfo = null;
        if (userRequest.getClientRegistration().getRegistrationId().equals("google")) {
            System.out.println("구글 로그인 요청");
            oAuth2UserInfo = new GoogleUserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("facebook")) {
            System.out.println("페이스북 로그인 요청");
            oAuth2UserInfo = new FaceBookUserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("github")) {
            System.out.println("깃허브 로그인 요청");
            oAuth2UserInfo = new GitHubUserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("kakao")) {
            System.out.println("카카오 로그인 요청");
            oAuth2UserInfo = new KakaoUserInfo(oAuth2User.getAttributes());
        } else if (userRequest.getClientRegistration().getRegistrationId().equals("naver")) {
            System.out.println("네이버 로그인 요청");
            oAuth2UserInfo = new NaverUserInfo(oAuth2User.getAttributes());
        } else {
            System.out.println("우리는 구글과 페이스북만");
        }

        Optional<Account> userOptional =
                accountRepository.findByProviderAndProviderId(oAuth2UserInfo.getProvider(), oAuth2UserInfo.getProviderId());

        Account user;

        if (userOptional.isPresent()) {
            user = userOptional.get();
            // user가 존재하면 update 해주기
            user.setEmail(oAuth2UserInfo.getEmail());
            accountRepository.save(user);
        } else {
            // user의 패스워드가 null이기 때문에 OAuth 유저는 일반적인 로그인을 할 수 없음.
            user = Account.builder()
                    .nickname(oAuth2UserInfo.getProvider() + "_" + oAuth2UserInfo.getProviderId())
                    .email(oAuth2UserInfo.getEmail())
                    .name(oAuth2UserInfo.getName())
                    .password(bCryptPasswordEncoder.encode("oauth2_password"))
                    .roles("USER")
                    .provider(oAuth2UserInfo.getProvider())
                    .providerId(oAuth2UserInfo.getProviderId())
                    .build();
            accountRepository.save(user);
        }

        return new UserAccount(user, oAuth2User.getAttributes());
    }

}

OAuth2SuccessHandler

AuthenticationSuccessHandler을 상속 받은 커스텀 클래스. RedirectStrategy을 이용해 소셜 로그인 성공 후 이동할 url을 지정한다. 

@Component
@RequiredArgsConstructor
public class OAuth2SuccessHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler {
    private final JWTUtil jwtUtil;
    private final ObjectMapper objectMapper;
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    protected Log logger = LogFactory.getLog(this.getClass());



    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {

//        SecurityContextHolder.getContext().setAuthentication(authentication);


        response.addHeader(JWTUtil.AUTHORIZATION_HEADER, JWTUtil.BEARER + jwtUtil.generate(authentication));
        handle(request, response, authentication);
        clearAuthenticationAttributes(request);


    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }


    protected void handle(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication
    ) throws IOException {

        String targetUrl = determineTargetUrl(authentication);

        if (response.isCommitted()) {
            logger.debug(
                    "Response has already been committed. Unable to redirect to "
                            + targetUrl);
            return;
        }

        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(final Authentication authentication) {

        Map<String, String> roleTargetUrlMap = new HashMap<>();
        roleTargetUrlMap.put("ROLE_USER", "/");
        roleTargetUrlMap.put("ROLE_ADMIN", "/");

        final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        for (final GrantedAuthority grantedAuthority : authorities) {
            String authorityName = grantedAuthority.getAuthority();
            if(roleTargetUrlMap.containsKey(authorityName)) {
                return roleTargetUrlMap.get(authorityName);
            }
        }

        throw new IllegalStateException();
    }

    protected void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return;
        }
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }



}

SecurityConfig

CustomOAuth2UserService와 OAuth2SuccessHandler을 설정 메소드에 등록한다.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JWTLoginFilter jwtLoginFilter = new JWTLoginFilter(objectMapper, jwtUtil, accountService, authenticationManager());
        JWTCheckFilter jwtCheckFilter = new JWTCheckFilter(authenticationManager(), accountService, jwtUtil);

        http.
                csrf().disable()
                .authorizeRequests().antMatchers("/", "/css/**", "/img/**", "/js/**", "/h2-console/**").permitAll()
                .and()
                .formLogin(
                        config -> {
                            config.loginPage("/login")
                                    .successForwardUrl("/")
                                    .failureForwardUrl("/login?error=true");
                        }
                )
                .addFilter(jwtLoginFilter)
                .addFilter(jwtCheckFilter)

                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()



                .oauth2Login(oauth -> {
                    oauth
                            .userInfoEndpoint(userinfo -> {
                                userinfo.userService(customOAuth2UserService);

                            })
                            .successHandler(oAuth2SuccessHandler)
                            .loginPage("/login");
                });

    }

참고

https://www.baeldung.com/spring_redirect_after_login

'Programming > Spring' 카테고리의 다른 글

Spring Security: Authentication  (0) 2022.01.21
The Custom Authentication Success Handle  (0) 2022.01.20
OAuth2(2) OAuth2 Client 라이브러리 없이 카카오 로그인  (0) 2022.01.20
OAuth2(1) OAuth2 구성 및 동작  (0) 2022.01.18
CORS  (0) 2021.12.14
'Programming/Spring' 카테고리의 다른 글
  • Spring Security: Authentication
  • The Custom Authentication Success Handle
  • OAuth2(2) OAuth2 Client 라이브러리 없이 카카오 로그인
  • OAuth2(1) OAuth2 구성 및 동작
사랑우주인
사랑우주인
  • 사랑우주인
    lovelyAlien
    사랑우주인
  • 전체
    오늘
    어제
  • 글쓰기
    관리
    • 분류 전체보기 (209)
      • Programming (4)
        • Spring (28)
        • Java (46)
        • JPA (2)
        • 디자인 패턴 (5)
        • 개발&아키텍처 (0)
      • Network (14)
      • OS (19)
      • Database (1)
      • Kubernetes (0)
      • Kafka (2)
      • Algorithm (49)
        • BaekJoon (1)
        • Programmers (19)
        • Algorithm (5)
        • Socar (2)
        • LeetCode (19)
      • Interview (2)
      • Issues (2)
      • DotJoin (1)
      • Git (4)
      • 독서 (3)
      • 끄적끄적 (1)
      • 외부활동 (26)
        • 항해플러스 (2)
        • JSCODE 네트워크 (19)
        • JSCODE 자바 (5)
      • SQL (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • GitHub
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    socar
    디자인 패턴
    Climbing Stairs
    fcfs
    LinkedList
    제네릭
    OS
    운영체제
    runner 기법
    @JsonProperty
    algorithm
    wildcards
    JSCode
    AuthenticationSuccessHandler
    준영속 엔티티
    Thread
    rotting oranges
    Oauth2
    Reorder List
    clone graph
    Process
    lower bounded wildcards
    pacific atlantic water flow
    트랜잭션
    @JsonNaming
    RR
    BFS
    minimum number of arrows to burst balloons
    Generic
    추상화 클래스
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.1
사랑우주인
OAuth2(3) OAuth2 Client 라이브러리 사용 카카오 로그인
상단으로

티스토리툴바