카카오 사용자 정보로 회원가입 구현하기 위해선 먼저 카카오로부터 사용자 정보를 받아와야 합니다.
Step 1. html에서 인가코드 요청하기
<button id="login-kakao-btn" onclick="location.href='https://kauth.kakao.com/oauth/authorize?client_id=76cee502ebe1b5ed9aeba09f9a0ecdf7&redirect_uri=http://localhost:8080/api/user/kakao/callback&response_type=code'">
2. Controller
- 카카오에서 보내주는 '인가 코드' 처리하여 토큰 생성하고 반환하기
@GetMapping("/user/kakao/callback")
public String kakaoLogin(@RequestParam String code, HttpServletResponse response) throws JsonProcessingException {
String token = kakaoService.kakaoLogin(code);
Cookie cookie = new Cookie(JwtUtil.AUTHORIZATION_HEADER, token.substring(7));
cookie.setPath("/");
response.addCookie(cookie);
return "redirect:/";
}
3. Service
- Step 2 - getToken 메서드: '인가 코드'로 액세스 '토큰' 받아오기
- Step 3 - getKakaoUserInfo 메서드: 받아온 '토큰'으로 '카카오 사용자 정보' 가져오기
- 그림에 대한 내용은 Step3으로 끝입니다.
- registerKakaoUserIfNeeded 메서드: 필요 시 회원 가입
- 우리의 서비스를 이용하기 위한 토큰 반환
@Service
@RequiredArgsConstructor
public class KakaoService {
private final PasswordEncoder passwordEncoder;
private final UserRepository userRepository;
private final RestTemplate restTemplate;
private final JwtUtil jwtUtil;
private final RestTemplateConfig restTemplateConfig;
public String kakaoLogin(String code) throws JsonProcessingException {
String accessToken = getToken(code);
KakaoUserInfoDto kakaoUserInfo = getKakaoUserInfo(accessToken);
User kakaoUser = registerKakaoUserIfNeeded(kakaoUserInfo);
return jwtUtil.createToken(kakaoUser.getUsername(), kakaoUser.getRole());
}
private String getToken(String code) throws JsonProcessingException {
// 요청 URL 만들기
URI uri = UriComponentsBuilder
.fromUriString("https://kauth.kakao.com")
.path("/oauth/token")
.encode()
.build()
.toUri();
// HTTP Header 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
// HTTP Body 생성
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "authorization_code");
body.add("client_id", "76cee502ebe1b5ed9aeba09f9a0ecdf7");
body.add("redirect_uri", "http://localhost:8080/api/user/kakao/callback");
body.add("code", code);
RequestEntity<MultiValueMap<String, String>> requestEntity = RequestEntity
.post(uri)
.headers(headers)
.body(body);
// HTTP 요청 보내기
ResponseEntity<String> response = restTemplate.exchange(
requestEntity,
String.class
);
// HTTP 응답 (JSON) -> 액세스 토큰 파싱
JsonNode jsonNode = new ObjectMapper().readTree(response.getBody());
return jsonNode.get("access_token").asText();
}
private KakaoUserInfoDto getKakaoUserInfo(String accessToken) throws JsonProcessingException {
// 요청 URL 만들기
URI uri = UriComponentsBuilder
.fromUriString("https://kapi.kakao.com")
.path("/v2/user/me")
.encode()
.build()
.toUri();
// HTTP Header 생성
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
RequestEntity<MultiValueMap<String, String>> requestEntity = RequestEntity
.post(uri)
.headers(headers)
.body(new LinkedMultiValueMap<>());
// HTTP 요청 보내기
ResponseEntity<String> response = restTemplate.exchange(
requestEntity,
String.class
);
JsonNode jsonNode = new ObjectMapper().readTree(response.getBody());
Long id = jsonNode.get("id").asLong();
String nickname = jsonNode.get("properties")
.get("nickname").asText();
String email = jsonNode.get("kakao_account")
.get("email").asText();
return new KakaoUserInfoDto(id, nickname, email);
}
private User registerKakaoUserIfNeeded(KakaoUserInfoDto kakaoUserInfo) {
// DB 에 중복된 Kakao Id 가 있는지 확인
Long kakaoId = kakaoUserInfo.getId();
User kakaoUser = userRepository.findByKakaoId(kakaoId).orElse(null);
if (kakaoUser == null) {
// 카카오 사용자 email 동일한 email 가진 회원이 있는지 확인
String kakaoEmail = kakaoUserInfo.getEmail();
User sameEmailUser = userRepository.findByEmail(kakaoEmail).orElse(null);
if (sameEmailUser != null) {
kakaoUser = sameEmailUser;
// 기존 회원정보에 카카오 Id 추가
kakaoUser = kakaoUser.kakaoIdUpdate(kakaoId);
} else {
// 신규 회원가입
// password: random UUID
String password = UUID.randomUUID().toString();
String encodedPassword = passwordEncoder.encode(password);
// email: kakao email
String email = kakaoUserInfo.getEmail();
kakaoUser = new User(kakaoUserInfo.getNickname(), encodedPassword, email, UserRoleEnum.USER, kakaoId);
}
userRepository.save(kakaoUser);
}
return kakaoUser;
}
}
'Spring > 팀스파르타' 카테고리의 다른 글
50. ExceptionHandler, Spring의 Global 예외처리 (0) | 2024.12.06 |
---|---|
49. Spring AOP (0) | 2024.12.06 |
47. 소셜 로그인 - OAuth (0) | 2024.12.06 |
44. Mockito (0) | 2024.12.06 |
43. 단위 테스트 (0) | 2024.12.06 |