카카오 로그인을 구현하기 위한 애플리케이션 생성이 진행 되었다는 가정하에 작성된 내용입니다.
기본적으로 카카오 로그인 페이지를 호출하기 위해
https://kauth.kakao.com/oauth/authorize 로 client_id redirect_uri response_type 을 파라미터에 붙여 접속해야 합니다.
이 때 CORS가 발생할 수 있으니 주의해야합니다.
CORS에 대해서 알고 싶으시다면 👉 https://velog.io/@dbxlf3018/CORS 👈
카카오 로그인 페이지에 접속하여 로그인이 정상적으로 끝나게 되면 작성한 redirectUri로 인가코드를 넘겨받게 됩니다.
public String oauthRedirect(HttpServletRequest request){
// 카카오로부터 인가코드를 파라미터로 전달 받음
String code = request.getParameter("code");
try {
// 전달받은 인가코드를 통해 accessToken 발급
// OAuthToken 객체는 토큰을 넘겨받기 위해 생성한 별도의 객체
OAuthToken oAuthToken = kakaoApi.getAccessToken(code);
// 발급받은 토큰을 통해 사용자 정보 조회
KakaoProfile profile = kakaoApi.getUserInfo(oAuthToken.getAccessToken());
}catch(Exception e) {
e.printStackTrace();
}
return "/login/redirect";
}
반환받은 인가코드를 통해 카카오로 부터 인증 토큰을 발급받고 그 토큰을 가지고 로그인한 사용자의 정보를 받아올 수 있습니다.
/**
* 인가 코드를 받아 accessToken을 반환하는 메소드
*/
public OAuthToken getAccessToken(String code) {
RestTemplate rt = new RestTemplate();
//HttpHeader 오브젝트
HttpHeaders headers = new HttpHeaders();
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
//HttpBody 오브젝트
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_id", kakaoApiKey);
params.add("redirect_uri", redirectUri);
params.add("code", code);
//http 바디(params)와 http 헤더(headers)를 가진 엔티티
HttpEntity<MultiValueMap<String, String>> kakaoTokenRequest =
new HttpEntity<>(params, headers);
//reqUrl로 Http 요청 , POST 방식
ResponseEntity<String> response = rt.exchange(token, HttpMethod.POST, kakaoTokenRequest, String.class);
String responseBody = response.getBody();
// GsonBuilder를 사용해서 camelCase를 적용하여 OAuthToken의 객체에 값 적용
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
OAuthToken oAuthToken = gson.fromJson(responseBody, OAuthToken.class);
return oAuthToken;
}
넘겨받는 토큰을 저장할 수 있는 간단한 객체를 만들었습니다.
@Getter
@Setter
public class OAuthToken {
private String accessToken;
private String refreshToken;
private Date accessTokenExpiresAt;
private Date refreshTokenExpiresAt;
private String idToken;
private List<String> scopes;
}
인증 토큰을 카카오 프로필 호출 url에 같이 담아 보내 사용자의 프로필 정보를 반환받을 수 있습니다.
public KakaoProfile getUserInfo(String accessToken){
RestTemplate rt = new RestTemplate();
//HttpHeader 오브젝트
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
//Http 헤더를 가진 엔티티
HttpEntity<MultiValueMap<String,String>> kakaoProfileRequest = new HttpEntity<>(headers);
//카카오 프로필 호출 url로 Http요청(POST)
ResponseEntity<String> response = rt.exchange(profile, HttpMethod.POST, kakaoProfileRequest, String.class);
KakaoProfile kakaoProfile = new KakaoProfile(response.getBody());
return kakaoProfile;
}
넘어오는 프로필 정보 중 동의를 받는 정보일 경우 kakao_account 객체 안에 정보가 담겨있어 KakaoProfile에 저장 시 별도의 처리를 해주었습니다.
@Getter
@Setter
public class KakaoProfile {
// 카카오 식별 아이디값
private Integer id;
// 로그인 시간
private Date connectedAt;
// 이메일
private String email;
// 프로필 정보 저장 시 데이터 가공 처리
public KakaoProfile(String jsonResponseBody){
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(jsonResponseBody);
JsonObject kakaoAccount = element.getAsJsonObject().get("kakao_account").getAsJsonObject();
this.id = element.getAsJsonObject().get("id").getAsInt();
this.email = kakaoAccount.get("email").getAsString();
String connected_at = element.getAsJsonObject().get("connected_at").getAsString();
connected_at = connected_at.substring(0, connected_at.length() - 1);
LocalDateTime connectDateTime = LocalDateTime.parse(connected_at, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));
this.connectedAt = Date.valueOf(connectDateTime.toLocalDate());
}
}
이렇게 반환받은 정보를 토대로 DB에 저장 후 세션에 담아 화면에서 로그인 관련 처리를 진행할 수 있습니다.
카카오의 경우 사용자별 고유의 ID값이 같이 넘어오기 때문에 한번 DB에 저장하면 다음에 로그인 했을 때 이미 등록된 사용자인지 확인할 수 있습니다.