Oauth2 login을 구현해보자!
public JwtTokenDto loginOauth2(LoginOauth2Rq rq) {
ClientType clientType = rq.getClientType();
String code = rq.getCode();
if (KAKAO.equals(clientType)) {
return oauth2KakaoService.getToken(code);
}
if (GOOGLE.equals(clientType)) {
return oauth2GoogleService.getToken(code);
}
throw new AuthenticationException();
}
public JwtTokenDto getToken(String code) {
String kakaoToken = getKakaoToken(code);
Member member = getMemberByKaKaoToken(kakaoToken);
// 로그인 로그
MemberLogInLog memberLogInLog = MemberLogInLog.create(member);
memberLogInLogRepository.save(memberLogInLog);
return jwtTokenFactory.generateJwtToken(member);
}
private String getKakaoToken(String code) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
LinkedMultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add(KakaoConstants.CLIENT_ID, clientId);
params.add(KakaoConstants.REDIRECT_URI, redirectUri);
params.add(KakaoConstants.GRANT_TYPE, grantType);
params.add(KakaoConstants.CODE, code);
HttpEntity<LinkedMultiValueMap<String, String>> httpEntity = new HttpEntity<>(params,
headers);
JSONObject jsonObject = getResponse(httpEntity, TOKEN_URL);
return (String) jsonObject.get(KakaoConstants.ACCESS_TOKEN);
}
POST /oauth/token HTTP/1.1
Host: kauth.kakao.com
Content-type: application/x-www-form-urlencoded;charset=utf-8
요청 방식
1. 메소드 : POST
2. url : https://kauth.kakao.com/oauth/token
Header
1. contentType : x-www-form-urlencoded
Body(필수)
1. code
2. client_id
3. redirect_uri
4. grant_type
private JSONObject getResponse(HttpEntity<LinkedMultiValueMap<String, String>> httpEntity,
String url) {
try {
RestTemplate restTemplate = new RestTemplate();
// 여기서 .postForEntity를 통해 kakao api 로 요청함.
ResponseEntity<String> response = restTemplate.postForEntity(url, httpEntity,
String.class);
// body에 토큰이 담겨있음/
String body = response.getBody();
JSONParser jsonParser = new JSONParser();
return (JSONObject) jsonParser.parse(body)
} catch (ParseException e) {
throw new AuthenticationException();
}
}
private Member getMemberByKaKaoToken(String kakaoToken) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add(AUTHORIZATION, BEARER + kakaoToken);
HttpEntity<LinkedMultiValueMap<String, String>> httpEntity = new HttpEntity<>(headers);
JSONObject jsonObject = getResponse(httpEntity, USER_INFO_URL);
Map<String, Object> attributes = (Map<String, Object>) jsonObject.get(KakaoConstants.KAKAO_ACCOUNT);
String email = (String) attributes.get("email");
Member member = findMemberService.findByEmailAndClientTypeOrElseNull(email, KAKAO);
if (Objects.nonNull(member)) {
return member;
}
JSONObject profile = (JSONObject) attributes.get("profile");
String nickname = (String) profile.get("nickname");
member = Member.createCustomer(nickname, email, KAKAO);
// 회원가입 로그
memberRepository.save(member);
MemberSignUpLog memberSignUpLog = MemberSignUpLog.create(member);
memberSignUpLogRepository.save(memberSignUpLog);
return member;
}
GET/POST /v2/user/me HTTP/1.1
Host: kapi.kakao.com
Authorization: Bearer ${ACCESS_TOKEN}/KakaoAK ${APP_ADMIN_KEY}
Content-type: application/x-www-form-urlencoded;charset=utf-8
요청 방식
1. 메소드 : POST
2. url : https://kapi.kakao.com/v2/user/me
Header
1. contentType : x-www-form-urlencoded
2. Authorization(필수) : Bearer + ${ACCESS_TOKEN}
JwtTokenFactory
public JwtTokenDto generateJwtToken(Member member) {
Date now = DateUtils.now();
Date expiredDate = DateUtils.addTime(now, TOKEN_EXPIRE_TIME);
String token = Jwts.builder()
.setClaims(createClaims(member))
.setIssuedAt(now)
.setExpiration(expiredDate)
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact();
LocalDateTime expiredDateTime = LocalDateTime.ofInstant(expiredDate.toInstant(), ZoneId.systemDefault());
return JwtTokenDto.createJwtTokenDto(token, expiredDateTime);
}
이렇게 로그인이 완료되면, 다음 요청부터 받은 토큰을 헤더에 담아 요청을 보내 인증을 완료할 수 있다.
아래 글에서 JWT를 통해 인증을 하는지에 대해 설명한다.
https://velog.io/@suzhanlee/JWT-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0