[Spring Boot] 소셜로그인 구현하기 - 카카오편 (카카오, 구글, JWT ...)

    0.  소셜로그인 ?

     

     

     

    1.  카카오 소셜로그인 

    1. 카카오 로그인 과정

    1. 사용자가 서비스에서 카카오 로그인 버튼을 클릭하면 서비스는 카카오 인증 서버로 인가 코드 발급을 요청
    2. 카카오 인증 서버는 사용자에게 인증을 요청 (= 계정 정보를 입력해 로그인하는 화면 출력)
    3. 카카오 인증 서버는 사용자 인증 성공 시, 서비스 앱의 동의 항목 설정을 바탕으로 사용자에게 동의 화면을 출력
    4. 사용자가 필수 동의 항목에 동의하고 로그인을 요청하면, 카카오 인증 서버는 인가 코드(Authorization Code)를 발급해 서비스 앱에 등록된 Redirect URI로 전달
    5. 서비스는 전달받은 인가 코드로 토큰을 요청하여 받음

    2. 회원 확인 및 가입

    1. 서비스는 카카오 로그인을 완료하여 발급받은 토큰으로 사용자 정보 가져오기를 요청
    2. 카카오 API 서버는 요청 시 사용된 토큰의 유효성을 검증하고, 요청을 처리하고 서비스에 응답
    3. 서비스 서버는 카카오로부터 제공받은 사용자 정보로 해당 사용자가 서비스에 회원 가입되어 있는지 확인
      • 이미 회원 가입된 사용자: Step 3의 서비스 로그인 단계 수행
      • 아직 회원 가입되지 않은 사용자: 카카오에서 제공받은 사용자 정보로 서비스 데이터베이스에 회원 가입 처리

     

    2.  사전준비

    카카오 소셜로그인을 하기 위해서는 사전 설정이 필요하다. 

     

    2-1. 애플리케이션 추가하기

    앱 이름과 사업자명을 입력하고 저장을 누른다.

     

    2-1. 플랫폼 등록하기 

     

    2-2. 카카오 로그인 활성화

    [활성화 설정]의 [상태]가 [OFF]인 경우, 카카오 로그인 요청 시 KOE004 에러가 발생한다.

    그러므로 활성화 설정 상태를 ON로 설정하여 실제 서비에서 카카오 로그인 화면이 연결되도록 하자.

     

    2-3. 리다이렉트 URI 등록

    주의 사항

    • Redirect URI는 최대 10개까지 등록할 수 있습니다.
    • Redirect URI는 HTTP 및 HTTPS 프로토콜, 80, 443 포트를 허용합니다.
    • Redirect URI는 HTTP, HTTPS 프로토콜을 구분하므로 각각 등록해야 합니다.

    나의 경우 http://localhost:8080/app/users/kakao 으로 지정해주었다. (임의로 지정해주면 된다.)

     

    2-4. 동의항목

     

    [내 애플리케이션] > [카카오 로그인] > [동의 항목] > [개인정보]에서 설정가능하다.

    아래 사진과 같은 정보들을 가져올 수 있으며, 나의 경우에는 이메일만 받아오도록 설정해주었다.

     

    3. 자세히 알아보자

    사전 준비가 끝났다면 소셜로그인에 대한 과정을 자세히 알아보자.

    3-1. 인가코드 발급

     

    사용자가 카카오 로그인을 요청하게 되면, 카카오 서버는 Redirect URI로 인가코드(authorization code)를 발급하게 된다.

     

    인가코드 발급 시 필요한 필수 파라미터들

     

    GET /oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code

    애플리케이션을 등록하였다면 앱설정 > 요약정보 에서 자신의 앱키를 볼 수 있는데, 이때 Rest Api 키를 client_id에 넣어주면 된다.

    또한 redirect_uri의 경우 앞서 설정한 리다이렉트 주소를 넣어주면 된다!

     

    이 과정을 거쳤다면 다음과 같이 설정한 uri로 리다이렉트된 것을 볼 수 있고, code = ~~~로 인가코드가 발행된 것을 볼 수 있다.

     

     

    3-2. 액세스 토큰 발급

     

    앞서 발급한 인가코드로 카카오 서버에 액세스토큰을 요청할 수 있다.

    필수 파라미터를 포함해 POST/ouath/token으로 요청해야 하며, 요청 성공 시 응답은 토큰과 토큰 정보를 포함하게 된다.

    Rest APi 키와 리다이렉트 주소의 경우에는 외부로 노출시키지 않아야 하므로 application.yml에 지정하여주었다.

    @RequiredArgsConstructor
    @Service
    public class OAuthService {
    
        private final UserRepository userRepository;
    
        @Value("${spring.security.oauth2.client.registration.kakao.client-id}")
        private String kakao_client_id;
    
        @Value("${spring.security.oauth2.client.registration.kakao.redirect-uri}")
        private String kakao_redirect_uri;
    
        /* 액세스 토큰 발급 */
        public String getKakaoAccessToken (String code) {
            String accessToken = "";
            String refreshToken = "";
            String reqURL = "https://kauth.kakao.com/oauth/token";
    
            try {
                URL url = new URL(reqURL);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setDoOutput(true);
    
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
                StringBuilder sb = new StringBuilder();
                sb.append("grant_type=authorization_code");
                sb.append("&client_id="+kakao_client_id);
                sb.append("&redirect_uri="+kakao_redirect_uri);
                sb.append("&code=" + code);
                bw.write(sb.toString());
                bw.flush();
    
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line = "";
                String result = "";
    
                while ((line = br.readLine()) != null) {
                    result += line;
                }
    
                JsonElement element = JsonParser.parseString(result);
                accessToken = element.getAsJsonObject().get("access_token").getAsString();
                refreshToken = element.getAsJsonObject().get("refresh_token").getAsString();
    
                br.close();
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return accessToken;
        }
    }

     

    3-3. 사용자 정보 요청

     

    액세스토큰까지 발급받았다면, 이 액세스토큰을 통해 카카오 서버에 사용자의 정보를 요청할 수 있다.

    • 요청 URL : https://kapi.kakao.com/v2/user/me 
    • 요청 메서드 : POST
    • 헤더 : Authorization Bearer 액세스토큰
    @RequiredArgsConstructor
    @Service
    public class OAuthService {
        /* ... */
        
        public KakaoResponse getKakaoUserInfo(String accessToken) {
            HashMap<String, Object> userInfo = new HashMap<>();
            String reqURL = "https://kapi.kakao.com/v2/user/me";
    
            try {
                URL url = new URL(reqURL);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Authorization", "Bearer " + accessToken);
    
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line = "";
                String result = "";
    
                while ((line = br.readLine()) != null) {
                    result += line;
                }
    
                JsonElement element = JsonParser.parseString(result);
                JsonObject kakaoAccount = element.getAsJsonObject().get("kakao_account").getAsJsonObject();
                String email = kakaoAccount.getAsJsonObject().get("email").getAsString();
                String id = element.getAsJsonObject().get("id").getAsString();
                userInfo.put("email", email);
                userInfo.put("id", id);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            return new KakaoResponse((String)userInfo.get("id"), (String)userInfo.get("email"));
        }
    @Getter
    @AllArgsConstructor
    public class KakaoResponse {
        private String socialIdx;
        private String email;
    }

     

     

    4. 테스트 해보기

    컨트롤러의 전반적인 흐름은 다음과 같다

    • OAuthService의 getKakaoAccessToken()메서드에 요청 파라미터로 받은 인가코드를 전달하여 액세스 토큰은 발급 받는다.
    • OAuthService의 getKakaoUserInfo() 메서드에 액세스토큰을 파라미터로 전달하여 유저의 소셜 식별자와 이메일을 Json형태로 받는다. 
    @RestController
    @RequiredArgsConstructor
    @RequestMapping("/oauth")
    public class OAuthController {
        @ResponseBody
        @GetMapping("/kakao/info")
        public ResponseEntity<KakaoResponse> getKakaoUserInfo(@RequestParam String code) {
            String accessToken = OAuthService.getKakaoAccessToken(code);
            KakaoResponse kakaoUserInfo = OAuthService.getKakaoUserInfo(accessToken);
            return new ResponseEntity<>(kakaoUserInfo, HttpStatus.OK);
        }    
    }

     

    포스트맨 결과는 다음과 같다!

    소셜로그인 id와 이메일이 잘 발급된 것을 볼 수 있다.

     

    댓글