일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 한국건설관리시스템
- 자바
- abstract
- 집합_SET
- 제네릭
- 정수형타입
- EnhancedFor
- 대덕인재개발원
- 추상메서드
- 자동차수리시스템
- 메소드오버로딩
- 환경설정
- 예외처리
- 인터페이스
- 컬렉션프레임워크
- cursor문
- 다형성
- 사용자예외클래스생성
- 예외미루기
- 참조형변수
- 생성자오버로드
- NestedFor
- 객체 비교
- GRANT VIEW
- Java
- 오라클
- exception
- oracle
- 컬렉션 타입
- 어윈 사용법
- Today
- Total
거니의 velog
(40) 리액트 소셜 로그인 3 본문
4. API 서버에서 Access Token 처리
* 예제에서는 프론트 환경에서 Access Token까지 처리하고 API 서버에 이를 전달해서 API 서버 내에서 사용자와 관련된 처리를 하는 방식으로 구성할 것이다. 따라서, API 서버에 추가적인 기능을 개발해야 한다.
* 카카오 서비스에서 사용자 정보를 가져오기 위해서는 https://kapi.kakao.com/v2/user/me 를 Access Token을 이용해서 호출해야 한다.
https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#req-user-info
(1) MemberService의 개발
* API 서버에서는 Access Token으로 기존의 회원정보를 이용하거나 새로운 회원으로 추가할 것이므로 서비스 계층을 만들어서 처리한다. service 패키지에는 MemberService/MemberServiceImpl을 추가하고 accessToken을 파라미터로 받아서 로그인 처리에 사용하는 MemerDTO를 반환하는 getKakaoMember() 를 추가한다.
package com.unlimited.mallapi.service;
import org.springframework.transaction.annotation.Transactional;
import com.unlimited.mallapi.dto.MemberDTO;
@Transactional(rollbackFor = Exception.class)
public interface MemberService {
MemberDTO getKakaoMember(String accessToken);
}
* MemberServiceImpl 에서는 RestTemplate 을 이용해서 카카오 서비스를 호출한다. 호출 결과는 Map 타입으로 나오는데 이 중에서 이메일 주소를 추출한다.
package com.unlimited.mallapi.service;
import java.util.LinkedHashMap;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import com.unlimited.mallapi.dto.MemberDTO;
import com.unlimited.mallapi.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@Service
@RequiredArgsConstructor
@Log4j2
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
/**
* Kakao Access Token을 이용하여 Kakao 사용자 정보를 가져오는 메서드
*
* @param accessToken Kakao API에 접근하기 위한 Access Token
* @return Kakao 사용자 정보에 대한 DTO 객체
*/
@Override
public MemberDTO getKakaoMember(String accessToken) {
// Kakao API를 통해 사용자 이메일 정보를 얻어옴
String email = getEmailFromKakaoAccessToken(accessToken);
log.info("Kakao 사용자 이메일: " + email);
// 추후에 사용자 정보를 처리하는 로직이 구현되면 해당 정보를 담은 DTO를 반환
return null;
}
/**
* Kakao Access Token을 이용하여 Kakao API에 요청하여 사용자 이메일 정보를 가져오는 메서드
*
* @param accessToken Kakao API에 접근하기 위한 Access Token
* @return Kakao 사용자 이메일
*/
private String getEmailFromKakaoAccessToken(String accessToken) {
// Kakao API에서 사용자 정보를 가져오는 엔드포인트 URL
String kakaoGetUserURL = "https://kapi.kakao.com/v2/user/me";
// Access Token이 null일 경우 예외 발생
if (accessToken == null) {
throw new RuntimeException("Access Token이 null입니다.");
}
// RestTemplate을 사용하여 Kakao API에 요청을 보내고 응답을 받아옴
RestTemplate restTemplate = new RestTemplate();
// HTTP 요청 헤더 설정
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Bearer " + accessToken);
headers.add("Content-Type", "application/x-www-form-urlencoded");
HttpEntity<String> entity = new HttpEntity<>(headers);
// Kakao API 엔드포인트 URL을 사용하여 UriComponents 생성
UriComponents uriBuilder = UriComponentsBuilder.fromHttpUrl(kakaoGetUserURL).build();
// RestTemplate을 사용하여 Kakao API에 GET 요청을 보내고 응답을 받아옴
ResponseEntity<LinkedHashMap> response = restTemplate.exchange(
uriBuilder.toString(),
HttpMethod.GET,
entity,
LinkedHashMap.class);
// 응답 내용을 로깅
log.info("Kakao API 응답: " + response);
// 응답 내용에서 사용자 정보를 추출
LinkedHashMap<String, LinkedHashMap> bodyMap = response.getBody();
// 로깅
log.info("------------------------------------");
log.info("Kakao API 응답 내용: " + bodyMap);
// 응답 내용에서 Kakao 계정 정보를 추출
LinkedHashMap<String, String> kakaoAccount = bodyMap.get("kakao_account");
// 로깅
log.info("Kakao 계정 정보: " + kakaoAccount);
// Kakao 계정 정보에서 이메일을 추출하여 반환
return kakaoAccount.get("email");
}
}
(2) SocialController의 개발
* MemberService의 호출은 SocialController로 처리한다. 우선은 MemberService의 동작을 확인하는 목적으로 문자열의 배열과 같이 의미가 없는 결과를 반환하고 MemberService의 getMemberFromKakao() 를 호출하도록 작성한다.
package com.unlimited.mallapi.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.unlimited.mallapi.service.MemberService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@RestController
@Log4j2
@RequiredArgsConstructor
public class SocialController {
private final MemberService memberService;
/**
* Kakao Access Token을 이용하여 Kakao 사용자 정보를 가져오는 엔드포인트
*
* @param accessToken Kakao API에 접근하기 위한 Access Token
* @return 사용자 정보를 담은 배열 또는 메시지 (현재는 더미 데이터 반환)
*/
@GetMapping("/api/member/kakao")
public String[] getMemberFromKakao(@RequestParam("accessToken") String accessToken) {
log.info("Kakao 사용자 정보 조회를 위한 엔드포인트 호출");
log.info("전달받은 Access Token: " + accessToken);
// Kakao 사용자 정보 조회 서비스 호출
memberService.getKakaoMember(accessToken);
// 현재는 더미 데이터를 반환
return new String[] { "AAA", "BBB", "CCC" };
}
}
(3) 리액트의 호출 테스트
* 리액트에서는 인가 코드를 이용해서 API 서버를 호출하는 기능을 kakaoApi.js 내 getMemberWithAccessToken() 으로 추가한다.
import axios from "axios";
import { API_SERVER_HOST } from "./todoApi";
//const rest_api_key = `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`; // REST키값
const redirect_uri = `http://localhost:3000/member/kakao`;
const auth_code_path = `https://kauth.kakao.com/oauth/authorize`;
const access_token_url = `https://kauth.kakao.com/oauth/token`; // 추가
export const getKakaoLoginLink = () => {
const kakaoURL = `${auth_code_path}?client_id=${rest_api_key}&redirect_uri=${redirect_uri}&response_type=code`;
return kakaoURL;
};
export const getAccessToken = async (authCode) => {
const header = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
};
const params = {
grant_type: "authorization_code",
client_id: rest_api_key,
redirect_uri: redirect_uri,
code: authCode,
};
const res = await axios.post(access_token_url, params, header);
const accessToken = res.data.access_token;
return accessToken;
};
export const getMemberWithAccessToken = async (accessToken) => {
const res = await axios.get(
`${API_SERVER_HOST}/api/member/kakao?accessToken=${accessToken}`
);
return res.data;
};
* KakaoRedirectPage 에서는 Access Token을 받은 후 getMemberWithAccessToken()을 호출하도록 수정한다.
import React, { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import { getAccessToken, getMemberWithAccessToken } from "../../api/kakaoApi";
const KakaoRedirectPage = () => {
const [searchParams] = useSearchParams();
const authCode = searchParams.get("code");
useEffect(() => {
getAccessToken(authCode).then((accessToken) => {
console.log(accessToken);
getMemberWithAccessToken(accessToken).then((memberInfo) => {
console.log("-------------------");
console.log(memberInfo);
});
});
}, [authCode]);
return (
<div>
<div>Kakao Login Redirect</div>
<div>{authCode}</div>
</div>
);
};
export default KakaoRedirectPage;
* API 서버에서는 리액트에서 카카오 로그인을 수행하고 나면 Access Token이 API 서버에 전달되어서 처리되는 로그들을 확인할 수 있다.
'SpringBoot_React 풀스택 프로젝트' 카테고리의 다른 글
(42) 리액트 소셜 로그인 5 (0) | 2024.03.08 |
---|---|
(41) 리액트 소셜 로그인 4 (0) | 2024.03.07 |
(39) 리액트 소셜 로그인 2 (0) | 2024.03.07 |
(38) 리액트 소셜 로그인 1 (0) | 2024.03.06 |
(37) 리덕스 툴킷 6 (1) | 2024.03.06 |