서론.
해당 프로젝트에서는 오로지
카카오 소셜 로그인
만 사용한다. ( ID/PW 사용안함! )
이전 포스팅✅에서는 프론트에서 받은 인가코드로 카카오 서버에서 엑세스 토큰을 발급받았다.
이어서 발급받은 토큰을 이용해 해당 사용자의 프로필 정보를 받아 DB에 저장해보자.
기본 의존성 :
Spring Web
Spring boot DevTools
Lombok
Spring Security
MySQL Driver
spring Data JPA
추가한 의존성 :
jackson-databind
jackson-datatype-jsr310
java-jwt
카카오 개발자 사이트에서 내 어플리케이션을 만들었을때, 동의 항목도 설정했을 것이다. 혹시 하지 않았다면 지금이라도 설정하자.😙
동의 항목을 이렇게 세개 받도록 설정했다. 이 부분은 각자 필요한 정보에 동의 체크를 받으면 된다!
이전 포스팅에서 만들었던 api에 로직을 추가해줄 것이다.
발급받은 엑세스 토큰을 이용해 카카오 서버에서 사용자 정보를 요청하고, 그 사용자 정보를 DB에 저장하는 기능까지 넣어보겠다.
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserService userService;
// 프론트에서 인가코드 받아오는 url
@GetMapping("/oauth/token")
public User getLogin(@RequestParam("code") String code) {
// 넘어온 인가 코드를 통해 access_token 발급
OauthToken oauthToken = userService.getAccessToken(code);
//(1)
// 발급 받은 accessToken 으로 카카오 회원 정보 DB 저장
String User = userService.saveUser(oauthToken.getAccess_token());
return User;
}
}
UserService
에 해당 메소드를 추가해준다.@Service
public class UserService {
@Autowired
UserRepository userRepository;
. . . (생략)
public User saveUser(String token) {
//(1)
KakaoProfile profile = findProfile(token);
//(2)
User user = userRepository.findByKakaoEmail(profile.getKakao_account().getEmail());
//(3)
if(user == null) {
user = User.builder()
.kakaoId(profile.getId())
//(4)
.kakaoProfileImg(profile.getKakao_account().getProfile().getProfile_image_url())
.kakaoNickname(profile.getKakao_account().getProfile().getNickname())
.kakaoEmail(profile.getKakao_account().getEmail())
//(5)
.userRole("ROLE_USER").build();
userRepository.save(user);
}
return user;
}
//(1-1)
public KakaoProfile findProfile(String token) {
//(1-2)
RestTemplate rt = new RestTemplate();
//(1-3)
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + token); //(1-4)
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
//(1-5)
HttpEntity<MultiValueMap<String, String>> kakaoProfileRequest =
new HttpEntity<>(headers);
//(1-6)
// Http 요청 (POST 방식) 후, response 변수에 응답을 받음
ResponseEntity<String> kakaoProfileResponse = rt.exchange(
"https://kapi.kakao.com/v2/user/me",
HttpMethod.POST,
kakaoProfileRequest,
String.class
);
//(1-7)
ObjectMapper objectMapper = new ObjectMapper();
KakaoProfile kakaoProfile = null;
try {
kakaoProfile = objectMapper.readValue(kakaoProfileResponse.getBody(), KakaoProfile.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return kakaoProfile;
}
findProfile()
이라는 메소드를 이용해 엑세스 토큰으로 카카오 서버에서 사용자 정보를 가져온다. 해당 메소드는 saveUser()
메소드 아래에 구현한다.KakaoProfile
클래스를 만든다.(👇아래 참고)RestTemplate
객체를 만든다. 이후 이어질 부분은 이전 포스팅에서 설명했기 때문에 간단히 짚고 넘어가겠다.HttpHeader
객체를 생성한다.HttpHeader
와 HttpBody
정보를 하나의 객체에 담아준다.KakaoProfile
객체로 변환해 리턴해준다.UserReapository
에 만들어뒀던 findByKakaoEmail()
메소드를 이용해 User
객체에 담아준다.user
변수의 값이 null인지 아닌지로 판단한다. 만약 null 이라면 DB에 저장되지 않은 사용자이므로 사용자 저장 로직을 실행한다.Properties
가 아닌 KakaoAccount
에서 가져온다. 자세한 설명은 👇아래에 있다.ROLE_USER
로 고정한다.
내가 응답받은 Json 데이터의 구조는 아래와 같다.
만약 동의 항목 체크를 나와 다르게 했다면 콘솔에 한 번 찍어보고 만드는 것을 추천한다.
{
"id":{},
"connected_at":"{}",
"properties":{
"nickname":"{}",
"profile_image":"{}",
"thumbnail_image":"{}
},
"kakao_account":{
"profile_nickname_needs_agreement":false,
"profile_image_needs_agreement":false,
"profile":{
"nickname":"{}",
"thumbnail_image_url":"{}",
"profile_image_url":"{}",
"is_default_image":false
},
"has_email":true,
"email_needs_agreement":false,
"is_email_valid":true,
"is_email_verified":true,
"email":"{}"
}
}
만들어둔 model/oauth
패키지 안에 KakaoProfile
이라는 클래스를 만든다.
@Data
public class KakaoProfile {
public Long id;
public String connected_at;
public Properties properties;
public KakaoAccount kakao_account;
@Data
public class Properties { //(1)
public String nickname;
public String profile_image; // 이미지 경로 필드1
public String thumbnail_image;
}
@Data
public class KakaoAccount { //(2)
public Boolean profile_nickname_needs_agreement;
public Boolean profile_image_needs_agreement;
public Profile profile;
public Boolean has_email;
public Boolean email_needs_agreement;
public Boolean is_email_valid;
public Boolean is_email_verified;
public String email;
@Data
public class Profile {
public String nickname;
public String thumbnail_image_url;
public String profile_image_url; // 이미지 경로 필드2
public Boolean is_default_image;
}
}
}
Properties
클래스에서 가져오지 않는게 좋다!!Properties
클래스의 이미지는 null
이지만 KakaoAccount
클래스의 이미지는 null
이 아닌 경우가 있었다. DB 컬럼을 모두 not null
로 설정했다면 여기서 이미지 가져오는 거 추천한다. 이거 때문에 토큰까지 다 구현해놓고 오류가 나서 허겁지겁 바꿨던 기억이 있다...😢도움 받은 영상 :
https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9
마치며.
여기까지 잘 따라왔다면
UserController
에 만든 api를 동작 시켜보자. 정상적으로 정보를 넣은 상태라면KakaoProfile
객체에 값이 잘 담겨 있고, DB에도 사용자 정보가 잘 저장되어 있을 것이다.
다음은 JWT 토큰의 개념과 토큰 발급을 위한 준비과정에 대해 적어볼 예정이다. 많관부많관부~🥳💖
기대됩니다