[Spring] Authorization code Grant 3 - 카카오 로그인

류재성's avatar
Jun 05, 2024
[Spring] Authorization code Grant 3 - 카카오 로그인
 

1. 카카오 로그인 로직 구현하기

 
UserController
@GetMapping("/oauth/callback") public String callback(String code) { System.out.println("콜백 완료 : " + code); User sessionUser = userService.카카오로그인(code); session.setAttribute("sessionUser", sessionUser); return "redirect:/shop"; }
 
UserService
public void 카카오로그인(String code) { // 1. code로 카카오에서 토큰 받기 (위임완료) // 2. 토큰으로 사용자 정보 받기 (PK, Email) // 3. 해당정보로 DB조회 (있을수, 없을수) // 4. 있으면? - 조회된 유저정보 리턴 // 5. 없으면? - 강제 회원가입 // 유저네임 : (provider_pk) // 비밀번호 : UUID // 이메일 : email 받은 값 // 프로바이더 : kakao }
 
💡
카카오에 등록한 Redirect URI 주소에 연결된 서비스 코드를 만든다. 순서는 1. 토큰 받기 - 2. 토큰으로 사용자 정보 받기 - 3. 정보로 스프링 서버에서 DB 조회 후 로그인 OR 회원가입 과정을 거친다.
 

2. 카카오에서 토큰 받기

 
UserService/카카오로그인(){}
// 1.1 RestTemplate 설정 RestTemplate rt = new RestTemplate(); // 1.2 http header 설정 HttpHeaders headers = new HttpHeaders(); headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); // 1.3 http body 설정 MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); body.add("grant_type", "authorization_code"); body.add("client_id", REST API 키 넣으면 됨); body.add("redirect_uri", "http://localhost:8080/oauth/callback"); body.add("code", code); // 1.4 body+header 객체 만들기 HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers); // 1.5 api 요청하기 (토큰 받기) ResponseEntity<KakaoResponse.TokenDTO> response = rt.exchange( "https://kauth.kakao.com/oauth/token", HttpMethod.POST, request, KakaoResponse.TokenDTO.class); // 1.6 값 확인 System.out.println(response.getBody().toString());
 
notion image
 
카카오에서 받은 토큰을 확인할 수 있다.

3. 토큰으로 사용자 정보 받기

 
HttpHeaders headers2 = new HttpHeaders(); headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); headers2.add("Authorization", "Bearer "+response.getBody().getAccessToken()); HttpEntity<MultiValueMap<String, String>> request2 = new HttpEntity<>(headers2); ResponseEntity<KakaoResponse.KakaoUserDTO> response2 = rt.exchange( "https://kapi.kakao.com/v2/user/me", HttpMethod.GET, request2, KakaoResponse.KakaoUserDTO.class); System.out.println("response2 : "+response2.getBody().toString());
 

4. 받은 정보로 DB 조회

 
String username = "kakao_"+response2.getBody().getId(); User userPS = userRepository.findByUsername(username);
 
💡
아이디는 API 요청한 플랫폼(카카오, 네이버, 구글 등) + “_” + 전달받은 primary key 를 사용한다. 이렇게 만들면 아이디가 중복될 수 없다.
 
 
if(userPS != null){ System.out.println("회원 정보 있음. 강제로그인 진행"); return userPS; }else{ System.out.println("회원 정보 없음. 강제회원가입 and 강제로그인 진행"); // 5. 없으면? - 강제 회원가입 // 유저네임 : (provider_pk) // 비밀번호 : UUID // 이메일 : email 받은 값 // 프로바이더 : kakao User user = User.builder() .username(username) .password(UUID.randomUUID().toString()) .email(response2.getBody().getProperties().getNickname()+"@nate.com") .provider("kakao") .build(); User returnUser = userRepository.save(user); return returnUser; }
 
💡
조회된 데이터가 있다면 바로 로그인을 한다. 만약 데이터가 없다면 회원가입 후 로그인을 진행한다. 아이디는 : provider(카카오,네이버,구글 등)_pk 비밀번호 : UUID 사용 (비밀번호는 회원이 알 필요 없다.) 이메일 : 카카오에게 받은 이메일(현재는 이메일을 받을 수 없기 때문에 닉네임@nate.com 으로 등록한다.
 
 
UserService 전체 코드
package org.example.loginapp.user; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import java.util.UUID; @RequiredArgsConstructor @Service public class UserService { private final UserRepository userRepository; @Transactional public void 회원가입(String username, String password, String email) { User user = User.builder() .username(username) .password(password) .email(email) .build(); userRepository.save(user); } public User 로그인(String username, String password) { User user = userRepository.findByUsername(username); if(user == null){ throw new RuntimeException("아이디가 없습니다"); }else{ if(user.getPassword().equals(password)){ return user; }else{ throw new RuntimeException("비밀번호가 틀렸습니다"); } } } public User 카카오로그인(String code) { // 1. code로 카카오에서 토큰 받기 (위임완료) - oauth2.0 // 1.1 RestTemplate 설정 RestTemplate rt = new RestTemplate(); // 1.2 http header 설정 HttpHeaders headers = new HttpHeaders(); headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); // 1.3 http body 설정 MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); body.add("grant_type", "authorization_code"); body.add("client_id", REST API 키 넣으면 됨); body.add("redirect_uri", "http://localhost:8080/oauth/callback"); body.add("code", code); // 1.4 body+header 객체 만들기 HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers); // 1.5 api 요청하기 (토큰 받기) ResponseEntity<KakaoResponse.TokenDTO> response = rt.exchange( "https://kauth.kakao.com/oauth/token", HttpMethod.POST, request, KakaoResponse.TokenDTO.class); // 1.6 값 확인 System.out.println(response.getBody().toString()); // 2. 토큰으로 사용자 정보 받기 (PK, Email) HttpHeaders headers2 = new HttpHeaders(); headers2.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); headers2.add("Authorization", "Bearer "+response.getBody().getAccessToken()); HttpEntity<MultiValueMap<String, String>> request2 = new HttpEntity<>(headers2); ResponseEntity<KakaoResponse.KakaoUserDTO> response2 = rt.exchange( "https://kapi.kakao.com/v2/user/me", HttpMethod.GET, request2, KakaoResponse.KakaoUserDTO.class); System.out.println("response2 : "+response2.getBody().toString()); // 3. 해당정보로 DB조회 (있을수, 없을수) String username = "kakao_"+response2.getBody().getId(); User userPS = userRepository.findByUsername(username); // 4. 있으면? - 조회된 유저정보 리턴 if(userPS != null){ System.out.println("회원 정보 있음. 강제로그인 진행"); return userPS; }else{ System.out.println("회원 정보 없음. 강제회원가입 and 강제로그인 진행"); // 5. 없으면? - 강제 회원가입 // 유저네임 : (provider_pk) // 비밀번호 : UUID // 이메일 : email 받은 값 // 프로바이더 : kakao User user = User.builder() .username(username) .password(UUID.randomUUID().toString()) .email(response2.getBody().getProperties().getNickname()+"@nate.com") .provider("kakao") .build(); User returnUser = userRepository.save(user); return returnUser; } } }
 
notion image
notion image
 
DB에 회원가입이 완료되었다.
Share article
RSSPowered by inblog