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
  • 링크

  • 공지사항

  • 인기 글

  • 태그

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

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

티스토리툴바