Project

쿡핏(2) - feat.카카오로그인

codingtori 2025. 1. 19. 20:34

드디어....! 카카오 로그인 해결했음....으아아악...🥹

 

클라이언트로 리다이렉션 하고 나서 이제는 되겠지 했는데 그 이후에도 계속...안됨. token은 쿠키에 잘 저장되고 다시 우리 홈으로도 오는데 왜 안되지.....

 

//원래코드 - KakaoAuth.tsx

import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { AxiosInstance } from "../../api/axiosInstance";
import { PATHS } from '../../constants/paths';
import { useAuth } from '../../context/AuthContext';

const KakaoAuth = () => {
  const params = new URL(window.location.href).searchParams;
  const code = params.get("code");

  const navigate = useNavigate();

  // 사용자 정보 전역변수로 저장하기 위한 것
  const { setUserId, setNickname } = useAuth();

  //인가코드 백으로 보내기기
  useEffect(() => {

    const kakaoLogin = async () => {
      try {
        const res = await AxiosInstance({
          method: "GET",
          url: `${PATHS.KAKAO_REDIRECT}/?code=${code}`,
          data: { code },
          headers: {
            "Content-Type": "application/json;charset=utf-8", //json형태로 데이터를 보내겠다는뜻
            "Access-Control-Allow-Origin": "*", //이건 cors 에러때문에 넣어둔것. 당신의 프로젝트에 맞게 지워도됨
          },
          withCredentials: true,  //쿠키 포함 요청 보냄
        });

        const answer = res.data;
        console.log(answer);

        if (answer.user) {
          setUserId(answer.user.loginId);
          setNickname(answer.user.nickname);

          console.log(answer.user.nickname);
          navigate(PATHS.HOME);
        } else {
          console.error('No userData from the backend');
        }
      } catch (err) {
        console.error('Error during Kakao login', err);
      }
    };

    kakaoLogin();
  }, [code, navigate, setUserId, setNickname]); 


  return (
    <div className="bg-yellow-50 h-screen flex justify-center py-10">
        <div className="space-y-2 text-goldbrown-80 text-semibold">
            <p>로그인 중입니다.</p>
            <p>잠시만 기다려주세요.</p>
        </div>
    </div>
  );
}

문제1.

카카오 로그인 후 받은 사용자 정보를 전역 상태(setUserId, setNickname)에만 저장하고 있음. 이 상태는 페이지 새로고침이나 새로운 접속 시 초기화됨. 그런데 백엔드에서 프론트엔드로 리다이렉트할 때 페이지가 완전히 새로고침되어 저장된 데이터가 지워지는 문제 발생


문제2.

백엔드에서 REDIRECT_URI를 /auth/kakao/callback으로 해놨는데 /auth/kakao로 계속 보냄

따라서 백엔드에서 리다이렉션 URL을 이에 맞게 수정해줌

const clientRedirectUrl = `http://localhost:5173/?token=${encodeURIComponent(token)}&loginId=${encodeURIComponent(user.loginId)}&nickname=${encodeURIComponent(user.nickname)}`;

문제3.

HttpOnly 쿠키에 저장된 토큰은 유지되지만, 프론트엔드에서 직접 접근할 수가 없음

● 백엔드에서 설정한 HttpOnly 쿠키는 프론트에서 직접 접근할 수가 없음!  HttpOnly 쿠키는 Javascript에서 직접 접근이 불가함

→ 사용자 정보를 sessionStorage에 저장

//1차 수정코드
const KakaoAuth = () => {
  const params = new URL(window.location.href).searchParams;
  const code = params.get("code");

  const navigate = useNavigate();
  const { setUserId, setNickname } = useAuth();

  useEffect(() => {
    const kakaoLogin = async () => {
      try {
        const res = await AxiosInstance({
          method: "GET",
          url: `${PATHS.KAKAO_REDIRECT}/?code=${code}`,
          data: { code },
          headers: {
            "Content-Type": "application/json;charset=utf-8",
            "Access-Control-Allow-Origin": "*",
          },
          withCredentials: true,
        });

        const answer = res.data;
        console.log(answer);

        if (answer.user) {
          // 사용자 정보를 sessionStorage에 저장
          sessionStorage.setItem('user', JSON.stringify(answer.user));
          
          setUserId(answer.user.loginId);
          setNickname(answer.user.nickname);

          console.log(answer.user.nickname);
          navigate(PATHS.HOME);
        } else {
          console.error('No userData from the backend');
        }
      } catch (err) {
        console.error('Error during Kakao login', err);
      }
    };

    kakaoLogin();
  }, [code, navigate, setUserId, setNickname]);

  return (
    <div className="bg-yellow-50 h-screen flex justify-center py-10">
      <div className="space-y-2 text-goldbrown-80 text-semibold">
        <p>로그인 중입니다.</p>
        <p>잠시만 기다려주세요.</p>
      </div>
    </div>
  );
}

문제4.

URL에는 토큰과 사용자 정보가 정상적으로 전달되고 있는데도 sessionStorage에 저장 안됨. 그래서 정보를 프론트엔드에서 제대로 처리하지 못하고 있는 것 같아서 KakaoAuth 컴포넌트에서 URL 파라미터(정보) 직접 파싱하도록 변경 

const params = new URLSearchParams(location.search);
const token = params.get('token');
const loginId = params.get('loginId');
const nickname = params.get('nickname');

 

이때,

//1
const params = new URL(window.location.href).searchParams;

//2
const params = new URLSearchParams(window.location.search);

● 1은 전체 URL을 URL객체로 파싱 후 그 객체의 searchParams 속성을 사용하는 것

● 2는 URL의 쿼리 문자열 부분만 포함. 이 문자열을 직접 'URLSearchParams' 객체로 변환


useEffect() 안 VS 밖

 

● 안

    ○ 컴포넌트가 렌더링될 때마다 실행됨

    ○ URL 파라미터가 변경될 때마다 즉시 반영됨

    ○ 불필요한 재계산 가능

● 밖

    ○ 컴포넌트가 마운트되거나 의존성 배열의 값이 변경될 때만 실행됨

    ○ URL 파라미터 변경을 즉시 감지하지 못할 수 있음

    ○ 불필요한 재계산 방지 가능

 

** 마운트

: 해당 컴포넌트가 **DOM(Document Object Model)**에 처음으로 추가되어 브라우저 화면에 렌더링되는 과정을 의미

 

(+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++)

컴포넌트 라이프 사이클 : 생성 → 렌더링 → 업데이트 → 언마운트

  • 마운트 단계: 컴포넌트가 생성되고 화면에 표시되는 단계
  • 업데이트 단계: 상태(state)나 props가 변경되어 컴포넌트가 다시 렌더링되는 단계
  • 언마운트 단계: 컴포넌트가 화면에서 제거되는 단계

마운트 될때 실행되는 작업들

 

  • 생성자(constructor) 실행 (클래스형 컴포넌트의 경우)
  • 초기 상태(state) 설정
  • render() 메서드 실행 또는 함수형 컴포넌트의 리턴값이 렌더링
  • 컴포넌트가 DOM에 추가됨
  • 마운트 완료 후 추가 작업 수행 가능 (클래스형: componentDidMount, 함수형: useEffect(() => {}, [])

(+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++)

카카오 로그인의 경우, URL 파라미터는 컴포넌트가 처음 로드될 때 한 번만 필요  → useEffect()안에서 파싱하도록 설정


문제 5.

이렇게 했는데도... 꿈쩍도 안함... 심지어 `console.log(answer)` 도 실행 안 되는걸 보고 이상함을 감지함.... KakaoAuth 컴포넌트 자체가 제대로 실행되지 않는 것 같음 감지.... 그래서 맨 윗줄에 실행되는 지 확인 코드를 넣었는데도 안뜨는 걸 보고 문제 파악..완료....🔫

 

백엔드에서 이미 다 처리하고 프론트에서는 리다이렉트한 정보를 사용하기만 하기 때문에 굳이 AxiosInstance를 사용한 GET 요청 부분은 불필요!!!! 이 부분을 삭제!

 

따라서, App.tsx 의 PATHS.KAKAO_CALLBACK 안의 PATHS가 원래는 

export const PATHS = {
    HOME: '/',
    HISTORY: '/history',
    FAVORITE: '/favorite',
    RECOMMEND: '/recommend',
    LOGIN: '/login',
    SIGNUP: '/signup',
    KAKAO_REDIRECT: `${BASE_URL}/auth/kakao`,
    KAKAO_CALLBACK: `${BASE_URL}/auth/kakao/callback`,
};

//이때, BASE_URL은 `https://localhost:3000`

이렇게 되어있었는데, 이때 BASE_URL은 API 요청을 위한 것이므로, 필요없음 ! 그래서 KAKAO_CALLBACK에서 제거~! 

 

최종 프로세스 흐름

1. 사용자가 카카오 로그인 선택

2. 카카오 서버가 인가 코드 제공

3. 백엔드에서 인가 코드로 카카오 Access Token 요청

4. 카카오 Access Token으로 사용자 정보 요청

5. 사용자 정보로 JWT 토큰 생성

6. JWT 토큰을 클라이언트에 전달

 

로그인 완료된 화면

 

히히 아직 디자인도 수정해야되고 API 연결 등등 수정해야할게 많지만 큰 산 하나 넘었다 ~!!

원래 배포까지는 결정 안됐었는데 하기로 했고 그러니까 원래는 chatgpt-api사용하려했는데 돈내야 하기도 하고 csv에서 추천된 메뉴를 chatgpt로 레시피 생성해버리면 사용되는 재료가 달라지는 문제가 발생하여 공공API 사용하는 방향으로 바꾸기로 했다.

!끝까지 화이팅!