2022년 4월 16일(토)
[스파르타코딩클럽] Spring 심화반 - 2주차 - 3
https://kauth.kakao.com/oauth/authorize?client_id=본인의 REST API키&redirect_uri={REDIRECT_URI}&response_type=code
@GetMapping("/user/kakao/callback")
public String kakaoLogin(@RequestParam String code) {
// authorizedCode: 카카오 서버로부터 받은 인가 코드
KakaoUserService.kakaoLogin(code); // userService.kakaoLogin 에서 나머지 처리
return "redirect:/";
}
public void kakaoLogin(String code) throws JsonProcessingException {
// 1. "인가 코드"로 "액세스 토큰" 요청
// 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", "본인의 REST API키");
body.add("redirect_uri", "http://localhost:8080/user/kakao/callback");
body.add("code", code);
// HTTP 요청 보내기
HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest =
new HttpEntity<>(body, headers);
RestTemplate rt = new RestTemplate();
ResponseEntity<String> response = rt.exchange(
"https://kauth.kakao.com/oauth/token",
HttpMethod.POST,
kakaoTokenRequest,
String.class
);
// HTTP 응답 (JSON) -> 액세스 토큰 파싱
String responseBody = response.getBody();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(responseBody);
String accessToken = jsonNode.get("access_token").asText();
}
// 2. 토큰으로 카카오 API 호출
// HTTP Header 생성
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
// HTTP 요청 보내기
HttpEntity<MultiValueMap<String, String>> kakaoUserInfoRequest = new HttpEntity<>(headers);
response = rt.exchange(
"https://kapi.kakao.com/v2/user/me",
HttpMethod.POST,
kakaoUserInfoRequest,
String.class
);
responseBody = response.getBody();
jsonNode = objectMapper.readTree(responseBody);
Long id = jsonNode.get("id").asLong();
String nickname = jsonNode.get("properties")
.get("nickname").asText();
String email = jsonNode.get("kakao_account")
.get("email").asText();
System.out.println("카카오 사용자 정보: " + id + ", " + nickname + ", " + email);
설계: 사람마다 여러가지로 할 수 있지만, 아래 프로젝트에서는 다음과 같이 실행
User 테이블에 'kakaoId' 추가 (nullable true, unique true)
회원 가입 : kakaoId 를 가진 회원이 없는 경우에만 회원 가입
// DB 에 중복된 Kakao Id 가 있는지 확인
Long kakaoId = kakaoUserInfo.getId();
User kakaoUser = userRepository.findByKakaoId(kakaoId)
.orElse(null); // UserRepository 설정 해주어야 함
if (kakaoUser == null) {
// 회원가입
// username: kakao nickname
String nickname = kakaoUserInfo.getNickname();
// password: random UUID
String password = UUID.randomUUID().toString();
String encodedPassword = passwordEncoder.encode(password);
// email: kakao email
String email = kakaoUserInfo.getEmail();
// role: 일반 사용자
UserRoleEnum role = UserRoleEnum.USER;
kakaoUser = new User(nickname, encodedPassword, email, role, kakaoId);
userRepository.save(kakaoUser);
}
// 4. 강제 로그인 처리
UserDetails userDetails = new UserDetailsImpl(kakaoUser);
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);