Skip to content

Commit

Permalink
#14 feat : kakao 연결 끊기 기능
Browse files Browse the repository at this point in the history
  • Loading branch information
sycuuui committed Sep 22, 2024
1 parent 69f7de6 commit e9cd36d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import Journey.Together.global.security.kakao.dto.KakaoProfile;
import Journey.Together.global.security.jwt.TokenProvider;
import Journey.Together.global.security.jwt.dto.TokenDto;
import Journey.Together.global.security.kakao.dto.KakaoToken;
import Journey.Together.global.security.naver.dto.NaverDeleteResponse;
import Journey.Together.global.security.naver.dto.NaverProperties;
import Journey.Together.global.security.naver.dto.NaverTokenResponse;
Expand Down Expand Up @@ -89,7 +90,7 @@ public LoginRes signIn(String token, String type, LoginReq loginReq) throws IOEx
interestRepository.save(interest);
}
tokenDto = tokenProvider.createToken(member);
member.setRefreshToken(tokenDto.refreshToken());
member.setRefreshToken(loginReq.refreshToken());

// Response
return LoginRes.of(member, tokenDto);
Expand Down Expand Up @@ -156,6 +157,16 @@ public void withdrawal(Member member) {
if(naverDeleteResponse.getError() != null){
throw new ApplicationException(ErrorCode.NAVER_DELETE_ERROR);
}
}else if(member.getLoginType().equals(LoginType.KAKAO)) {
//accessToken 요청
KakaoToken kakaoToken = kakaoClient.getKakaoAccessToken(member.getRefreshToken());
//연결 삭제
Long id = kakaoClient.unlinkUser(kakaoToken.access_token());
if(id==null){
throw new ApplicationException(ErrorCode.NAVER_REFRESH_ERROR);
}else if(!id.equals(member.getMemberId())){
throw new ApplicationException(ErrorCode.KAKAO_DELETE_ERROR);
}
}

memberRepository.delete(member);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public enum ErrorCode {
LOGOUT_TOKEN_EXCEPTION(HttpStatus.UNAUTHORIZED, 3003, "로그아웃된 토큰입니다"),
WRONG_TOKEN(HttpStatus.UNAUTHORIZED, 3004, "유효하지 않은 토큰입니다."),
WRONG_ACCESS_EXCEPTION(HttpStatus.BAD_REQUEST, 3005, "관리자만 접근 가능합니다."),

KAKAO_REFRESH_TOKEN_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 3006, "카카오 토큰에 오류가 있습니다"),
KAKAO_DELETE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, 3007, "카카오 연결 끊기에 실패하였습니다"),

//4000: Apply Error
NOT_APPLY_EXCEPTION(HttpStatus.BAD_REQUEST,4000,"지원 기간 지났습니다"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package Journey.Together.global.security.kakao;

import Journey.Together.global.security.kakao.dto.KakaoProfile;
import Journey.Together.global.security.kakao.dto.KakaoToken;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -21,9 +23,6 @@ public class KakaoClient {
@Value("${spring.security.oauth2.client.registration.kakao.client-secret}")
private String kakaoClientSecret;

@Value("${spring.security.oauth2.client.registration.kakao.authorization-grant-type}")
private String kakwaoGrantType;

@Value("${spring.security.oauth2.client.registration.kakao.redirect-uri}")
private String kakaoRedirectUri;

Expand All @@ -39,6 +38,44 @@ public class KakaoClient {
@Value("${spring.security.oauth2.client.withdrawal.unlink-url}")
private String unlinkUri;


/**
* 카카오 서버에 인가코드 기반으로 사용자의 토큰 정보를 조회하는 메소드
* @param refresh_token - 카카오에서 발급해준 refreshToken 코드
* @return - 카카오에서 반환한 응답 토큰 객체
*/
public KakaoToken getKakaoAccessToken(String refresh_token) {
// 요청 보낼 객체 기본 생성
WebClient webClient = WebClient.create(kakaoTokenUri);

//요청 본문
MultiValueMap<String , String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "refresh_token");
params.add("client_id", kakaoClientId);
params.add("refresh_token", refresh_token);
params.add("client_secret", kakaoClientSecret);

// 요청 보내기 및 응답 수신
String response = webClient.post()
.uri(kakaoTokenUri)
.header("Content-type", "application/x-www-form-urlencoded")
.body(BodyInserters.fromFormData(params))
.retrieve() // 데이터 받는 방식, 스프링에서는 exchange는 메모리 누수 가능성 때문에 retrieve 권장
.bodyToMono(String.class) // (Mono는 단일 데이터, Flux는 복수 데이터)
.block();// 비동기 방식의 데이터 수신

// 수신된 응답 Mapping
ObjectMapper objectMapper = new ObjectMapper();
KakaoToken kakaoToken;
try {
kakaoToken = objectMapper.readValue(response, KakaoToken.class);
} catch (Exception e) {
throw new RuntimeException(e);
}

return kakaoToken;
}

public KakaoProfile getMemberInfo(String accesToken) {
// 요청 기본 객체 생성
WebClient webClient = WebClient.create(kakaoUserInfoUri);
Expand All @@ -64,28 +101,27 @@ public KakaoProfile getMemberInfo(String accesToken) {
}

//카카오와 연결 끊기
public String unlinkUser(Long userId){
public Long unlinkUser(String accessToken){
// 요청 기본 객체 생성
WebClient webClient = WebClient.create(unlinkUri);
// 요청 보내서 응답 받기
String response = webClient.post()
.uri(unlinkUri)
.header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
.header("Authorization", "KakaoAK " + adminKey)
.header("Authorization", "Bearer " + accessToken)
.retrieve()
.bodyToMono(String.class)
.block();
// 수신된 응답 Mapping
ObjectMapper objectMapper = new ObjectMapper();

return response;
try {
JsonNode jsonNode = objectMapper.readTree(response);
if (jsonNode.has("id")) {
return jsonNode.get("id").asLong();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
// public String unlinkUser(Long userId) {
//
// URI uri = URI.create(KAKAO_UNLINK_URL + "?target_id_type=user_id&target_id=" + userId);
//
// RequestEntity<Void> request = new RequestEntity<>(headers, HttpMethod.POST, uri);
// ResponseEntity<String> response = restTemplate.exchange(request, String.class);
//
// }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package Journey.Together.global.security.kakao.dto;

import lombok.Builder;

@Builder
public record KakaoToken(
String access_token,
String refresh_token,
String token_type,
Integer expires_in,
Integer refresh_token_expires_in,
String scope
) {
}

0 comments on commit e9cd36d

Please sign in to comment.