1. 사용자가 로그인 버튼을 클릭
2. 프론트엔드는 사용자를 Kakao 로그인 페이지로 리다이렉션합니다.
3. 사용자가 Kakao 로그인 페이지에서 로그인을 수행하고 권한을 부여
4. 사용자가 로그인을 진행하고, 정보 사용에 동의한다.
5. 카카오 서버가 프론트에서 설정된 Redirect URI로 인증 결과를 전달하고 이 때 인가코드가 발급된다.
6. 백엔드 서버에서는 프론트엔드로부터 전달받은 인가코드를 사용하여 Kakao로부터 액세스 토큰 및 사용자 정보를 가져온다.
7. 사용자 정보를 활용해 JWT토큰을 생성하고 클라이언트에게 응답.
@PostMapping("/api/auth/kakao")
public ResponseEntity<AddInfoResponse> loginKakao(@RequestBody KakaoLoginParams params, HttpServletResponse response) {
AuthTokens authTokens = oAuthLoginService.login(params);
String accessToken = authTokens.getAccessToken();
String refreshToken = authTokens.getRefreshToken();
Long member_id = authTokens.getMember_id();
response.setHeader(jwtService.getAccessHeader(), "Bearer " + accessToken);
response.setHeader(jwtService.getRefreshHeader(), "Bearer " + refreshToken);
response.setHeader("member_id", member_id.toString());
return ResponseEntity.ok(new AddInfoResponse("Bearer", jwtService.getAccessTokenExpirationPeriod()));
}
public AuthTokens login(OAuthLoginParams params) {
OAuthInfoResponse oAuthInfoResponse = requestOAuthInfoService.request(params);
Long memberId = findOrCreateMember(oAuthInfoResponse);
Member member = memberRepository.findOne(memberId);
String accessToken = jwtService.createAccessToken(member.getEmail());
String refreshToken = jwtService.createRefreshToken();
memberRepository.saveRefreshToken(member.getEmail(), refreshToken);
return AuthTokens.of(memberId, accessToken, refreshToken);
}
private Long findOrCreateMember(OAuthInfoResponse oAuthInfoResponse) {
return memberRepository.findByEmail(oAuthInfoResponse.getEmail())
.map(Member::getId)
.orElseGet(() -> newMember(oAuthInfoResponse));
}
private Long newMember(OAuthInfoResponse oAuthInfoResponse) {
String email = oAuthInfoResponse.getEmail();
if (email == null) {
email = UUID.randomUUID() + "@nawabari.com";
}
Member member = Member.builder()
.kakao_id(oAuthInfoResponse.getKakao_id())
.age(oAuthInfoResponse.getAgeRange())
.gender(oAuthInfoResponse.getGender())
.socialType(SocialType.KAKAO)
.email(email)
.profile_nickname(oAuthInfoResponse.getNickname())
.profile_image(oAuthInfoResponse.getProfileImage())
.role(Role.GUEST)
.build();
memberRepository.save(member);
return member.getId();
}
@GetMapping("/login/oauth2/code/kakao")
public String loginKakao(@RequestParam("code") String code) {
KakaoLoginParams params = new KakaoLoginParams(code);
AuthTokens authTokens = oAuthLoginService.login(params);
String accessToken = authTokens.getAccessToken();
String refreshToken = authTokens.getRefreshToken();
Long memberId = authTokens.getMember_id();
return "<!DOCTYPE html>" +
"<html lang='en'>" +
"<head>" +
"<meta charset='UTF-8'>" +
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>" +
"<title>Redirect to App Test</title>" +
"</head>" +
"<body>" +
"<button onclick='redirectToApp()'>앱으로 돌아가기</button>" +
"<script>" +
"function redirectToApp() {" +
"window.location.href = 'callback-scheme://?access-token="+accessToken+"&refresh-token="+refreshToken+"&member-id="+memberId + "';" +
"}" +
"</script>" +
"</body>" +
"</html>";
}