ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Boot] Spring Security와 JWT를 이용한 OAuth2 로그인(카카오, 백엔드, 프론트의 흐름)
    백엔드 2023. 6. 27. 00:34

    * 이번 CEOS 프로젝트를 진행하며, 작성한 코드를 토대로 쉽게 흐름을 보기위해 정리한 글입니다.

     

     

     

    Spring Security란 인증과 인가(권한)에 대한 부분을 Filter에 따라 처리한다. Dispatcher servlet으로 가기 전에 적용되어 가장 먼저 URL 요청을 받는다. 여기서 인증이란 해당 사용자가 본인이 맞는지 확인하는 과정이며, 인가이란 인증된 사용자가 요청한 자원에 접근할 수 있는지 결정하는 과정이다. 즉, 인증을 성공해야 인가가 이루어진다.

     


     

     OAuth2 KAKAO Login을 살펴보자. 

    (카카오 서비스에서 신규 서비스를 등록하는 과정은 생략했습니다.)

     

    1. 사용자가 카카오 로그인을

    http://localhost:8080/oauth2/authorization/kakao?redirect_uri=

    라는 URL로 요청한다.

     

    2. 백엔드 서버는 위 요청을 

    https://kauth.kakao.com/oauth/authorize?client_id=

    라는 URL로 리다이렉트한다. 이때 client_id는 카카오 앱 설정에 등록한 client_id이다.

     

    3. 사용자의 브라우저에는 카카오 로그인 창이 띄워진다.

     

    4. 사용자가 카카오 로그인에 성공하면, 카카오는 

    http://localhost:8080/login/oauth2/code/kakao

    라는 redirect URL(내가 만듦)에 code를 담아서 보내준다. 나중에, AWS 서버에 배포하려면 주소를 추가해주어야 한다.

     

    5. code를 받은 Spring Security는 code와 Token을 맞바꾼다. 이 부분은 코드로 짠 기억이 없다. 알고 봤더니, Spring Security가 알아서 Token 받아오고, loadUser 불러서 OAuth2User Json을 만들어준다. 

    public class SecurityConfig {
        private final OAuthUserService oAuthUserService;
        private final JwtTokenProvider jwtTokenProvider;
        private final AuthenticationSuccessHandler authenticationSuccessHandler;
    
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors().configurationSource(corsConfigurationSource())
                .and()
                .httpBasic().disable()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers("**/oauth2/**","/kakaologin").permitAll()
                .anyRequest().authenticated()
                .and()
                    .logout()
                    .and()
                    .oauth2Login()
                    .successHandler(authenticationSuccessHandler)
                    .userInfoEndpoint()
                    .userService(oAuthUserService);
    
        return http.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class).build();
    }

     

    6. 백엔드 서버는 Token을 이용해 카카오에 회원 정보를 요청한다.

     

    7. 백엔드 서버는 회원 정보를 받아(OAuthUserService), JWT token을 생성한다(OAuth2SuccessHandler → JwtTokenProvider). 나는 accessToken만을 생성했다.

     

    OAuthUserService는 OAuth2User라는 회원 정보 JSON을 받아, 1) SessionUserDTO에 넣고 2) DB에 넣는다.

    {
    	"id": 숫자10자리,
    	"connected_at": "2022-06-24T06:49:55Z",
    	"properties": {
    		"nickname": "땡땡",
    		"profile_image": "http://k.kakaocdn.net/~~/img_640x640.jpg",
    		"thumbnail_image": "http://k.kakaocdn.net/~~/img_110x110.jpg"
    	},
    	"kakao_account": {
    		"profile_nickname_needs_agreement": false,
    		"profile_image_needs_agreement": false,
    		"profile": {
    				"nickname": "땡땡",
    				"thumbnail_image_url": "http://k.kakaocdn.net/~~/img_110x110.jpg",
    				"profile_image_url": "http://k.kakaocdn.net/~~/img_640x640.jpg",
    				"is_default_image": true
    		},
    		"has_email": true,
    		"email_needs_agreement": false,
    		"is_email_valid": true,
    		"is_email_verified": true,
    		"email": "~~"
    	}
    }​


    위 JSON을 가공해서 쓰기위해 DTO를 만든다.

     

    8. 백엔드 서버는 토큰과 첫로그인 여부를 URL parameter에 넣어 프론트로 보내준다.

     String token = jwtTokenProvider.createJwtAccessToken(oAuth2User.getAttribute("id").toString(), role); //토큰발행
            targetUrl = UriComponentsBuilder.fromUriString("http://localhost:8080/~")
                    .queryParam("Token", token)
                    .queryParam("FirstLogin", firstLogin)
                    .build().toUriString();
            getRedirectStrategy().sendRedirect(request, response, targetUrl);
    http://localhost:8080/kakaologin?Token=~&FirstLogin=false

     

    9. 프론트는 받은 JWT token을 로컬스토리지나 세션에 저장해 로그인을 유지한다.

     

    10. 프론트는 api를 백엔드 서버로 요청할 때, 헤더에 JWT token을 넣어 요청한다.

     

     


     

Designed by Tistory.