WebClient로 소셜로그인 구현하기:
WebClient 기본개념:
https://doinge-coding.tistory.com/entry/spring-webClient%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95
spring webClient를 적용해보자, spring webClient 사용 방법
회사 프로젝트에서 내부 curl을 쏴야하는 기능을 개발할 일이 생겼다. 특성상 spring batch랑은 어울리지 않아서 spring curl 라이브러리들을 찾던 중 spring webClient라는 것을 찾았다. Spring 어플리케이션
doinge-coding.tistory.com
스프링에서는 resttemplate보다 webclient 사용을 권장한다.
그래서 기존에 rest로 짜 놓았던 소셜로그인 코드를 webclient로 바꾸어보았다.
기존 코드는 이전 글 참조
카카오:
private String getKakaoAccessToken(String code) throws JsonProcessingException {
// 카카오에 보낼 api
WebClient client = WebClient.builder()
.baseUrl("https://kauth.kakao.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// 카카오 서버에 요청 보내기 & 응답 받기
JsonNode response = client.post()
.uri(uriBuilder -> uriBuilder
.path("/oauth/token")
.queryParam("grant_type", "authorization_code")
.queryParam("client_id", KAKAO_CLIENT_ID)
.queryParam("redirect_uri", KAKAO_REDIRECT_URI)
.queryParam("code", code)
.build())
.retrieve().bodyToMono(JsonNode.class).block();
return response.get("access_token").asText();
}
기존에 따로 entity에 담아 보내던 것들을 위의 형태로 담아 보낸다. 찾은 자료에서는 JSONObject로 받았으나 내용이 비어있는 형태로 전달되는 오류가 있어 JsonNode로 받게 되었다.
(JSONObject를 사용하기 위해서는 mavenrepo에서 json그래들을 추가해야 한다.)
JsonNode 형태로 응답을 바로 받아오기에 기존 코드보다 훨씬 짧아졌다.(파싱할 필요가 없어짐)
private KakaoUserInfoDto getKakaoUserInfo(String accessToken) throws JsonProcessingException {
// 카카오에 보낼 api
WebClient client = WebClient.builder()
.baseUrl("https://kapi.kakao.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// 카카오 서버에 요청 보내기 & 응답 받기
JsonNode response = client.post()
.uri(uriBuilder -> uriBuilder
.path("/v2/user/me")
.build())
.header("Authorization","Bearer " + accessToken)
.retrieve().bodyToMono(JsonNode.class).block();
Long id = response.get("id").asLong();
String nickname = response.get("properties")
.get("nickname").asText();
String email = response.get("kakao_account")
.get("email").asText();
return new KakaoUserInfoDto(id, nickname, email);
}
마찬가지로 헤더와 바디에 기존에 넣던 정보를 넣고 JsonNode로 받아온다.
public Member kakaoLogin(String code, HttpServletResponse response) throws JsonProcessingException {
System.out.println(code);
// 1. "인가 코드"로 "액세스 토큰" 요청
String accessToken = getKakaoAccessToken(code);
// 2. 토큰으로 카카오 API 호출
KakaoUserInfoDto kakaoUserInfo = getKakaoUserInfo(accessToken);
// DB 에 중복된 Kakao Id 가 있는지 확인
String kakaoId = kakaoUserInfo.getId().toString();
Member kakaoUser = memberRepository.findByKakaoId(kakaoId)
.orElse(null);
if (kakaoUser == null) {
// 회원가입
if(memberRepository.existsByEmail(kakaoUserInfo.getEmail()))
throw new IllegalArgumentException("이미 가입된 이메일입니다.");
Member member = Member.builder()
.email(kakaoUserInfo.getEmail())
.username(kakaoUserInfo.getNickname())
.password(passwordEncoder.encode(UUID.randomUUID().toString()))
.kakaoId(kakaoId)
.mail_auth(true)
.build();
memberRepository.save(member);
kakaoUser = member;
}
TokenDto tokenDto = tokenProvider.generateTokenDto(kakaoUser);
response.setHeader("Authorization","Bearer " + tokenDto.getAccessToken());
response.setHeader("Refresh-Token",tokenDto.getRefreshToken());
return kakaoUser;
}
이부분은 기존과 동일히다.
구글:
private String getGoogleAccessToken(String code) throws JsonProcessingException {
// 구글에 보낼 api
WebClient client = WebClient.builder()
.baseUrl("https://oauth2.googleapis.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// 구글 서버에 요청 보내기 & 응답 받기
JsonNode response = client.post()
.uri(uriBuilder -> uriBuilder
.path("/token")
.queryParam("code", code)
.queryParam("client_id", GOOGLE_CLIENT_ID)
.queryParam("client_secret", GOOGLE_CLIENT_SECRET)
.queryParam("redirect_uri", GOOGLE_REDIRECT_URI)
.queryParam("grant_type", "authorization_code")
.build())
.retrieve().bodyToMono(JsonNode.class).block();
return response.get("access_token").asText();
}
private GoogleUserInfoDto getGoogleUserInfo(String accessToken) throws JsonProcessingException {
// 구글에 보낼 api
WebClient client = WebClient.builder()
.baseUrl("https://www.googleapis.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
// 구글 서버에 요청 보내기 & 응답 받기
JsonNode response = client.get()
.uri(uriBuilder -> uriBuilder
.path("/oauth2/v1/userinfo")
.build())
.header("Authorization","Bearer " + accessToken)
.retrieve().bodyToMono(JsonNode.class).block();
String id = response.get("id").toString();
String name = response.get("name").toString();
String email = response.get("email").toString();
return new GoogleUserInfoDto(id,name,email);
}
public Member googleLogin(String code, HttpServletResponse response) throws JsonProcessingException {
// 1. "인가 코드"로 "액세스 토큰" 요청
String accessToken = getGoogleAccessToken(code);
// 2. 토큰으로 카카오 API 호출
GoogleUserInfoDto googleUserInfo = getGoogleUserInfo(accessToken);
// DB 에 중복된 Kakao Id 가 있는지 확인
String googleId = googleUserInfo.getId();
Member googleUser = memberRepository.findByGoogleId(googleId)
.orElse(null);
if(googleUser == null){
// 회원가입
Member member = Member.builder()
.email(googleUserInfo.getEmail())
.username(googleUserInfo.getName())
.password(passwordEncoder.encode(UUID.randomUUID().toString()))
.googleId(googleId)
.mail_auth(true)
.build();
memberRepository.save(member);
googleUser = member;
}
TokenDto tokenDto = tokenProvider.generateTokenDto(googleUser);
response.setHeader("Authorization","Bearer " + tokenDto.getAccessToken());
response.setHeader("Refresh-Token",tokenDto.getRefreshToken());
return googleUser;
}
구글도 동일하나 유저 정보를 가져올 때 post가 아닌 get으로 요청해야 한다는 차이점이 있다.
'TIL' 카테고리의 다른 글
2022.09.07.TIL (0) | 2022.09.07 |
---|---|
2022.09.01.TIL (0) | 2022.09.01 |
2022.08.30.TIL (시큐리티 복습) (0) | 2022.08.30 |
2022.08.25.TIL (0) | 2022.08.25 |
2022.08.23.TIL (0) | 2022.08.22 |