[데브코스/TIL] DAY52~53 - API & JWT Token

Minha Ahn·2025년 1월 3일
0

데브코스

목록 보기
36/42
post-thumbnail

🪁 API 연동

1. fetch

  • HTTP 요청을 보내는 데 사용되는 도구
  • 브라우저에서 기본적으로 제공하는 API
  • 따로 설치할 필요 없음
const getData = async () => {
  const response = await fetch("url")
  const data = await response.json();
}

2. axios

  • HTTP 요청을 보내는 데 사용되는 도구
  • 따로 라이브러리를 설치해야 함
  • 자동으로 json을 적용하여 response 객체를 바로 반환 (편리)
  • fetch에서는 없는 기능들 제공
const getData = async () => {
  const { data } = await axios.get("url");
}

3. CRUD

  • POST : 데이터 추가
  • PUT : 데이터 수정 (데이터 식별을 위한 고유 아이디를 제외한 모든 데이터 수정)
  • PATCH : 데이터 수정 (일부 내용만 수정)
  • DELETE : 데이터 삭제



🪁 JWT Token

1. 로그인 및 토큰 데이터를 전역 상태로 관리

import { create } from "zustand";

interface AuthStore {
  isLoggedIn: boolean;
  accessToken: string | null;
  login: (accessToken: string) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthStore>((set) => ({
  isLoggedIn: false,
  accessToken: null,
  login: (accessToken: string) => set({ isLoggedIn: true, accessToken }),
  logout: () => set({ isLoggedIn: false, accessToken: null }),
}));

2. 액세스 토큰을 API 요청에 액세스 토큰 담아 전송

export const axiosInstance = axios.create({
  baseURL: `${import.meta.env.VITE_API_URL}`,
  withCredentials: true,
});

axiosInstance.interceptors.request.use((config) => {
  const token = useAuthStore.getState().accessToken;
  if (token) {
    config.headers["Authorization"] = `Bearer ${token}`;
  }
  return config;
});

3. 액세스 토큰이 없어 에러가 발생, 리프레시 토큰으로 재발급하고 재요청

let retry = false;

axiosInstance.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    if (error.response?.status === 403 && !retry) {
      // retry를 설정해야 한 번만 실행됨. 그렇지 않으면 무한 루프에 빠짐
      console.log("token 실패");
      retry = true;
      try {
        const { data } = await axiosInstance.post("/token");
        console.log(data);
        useAuthStore.setState({
          accessToken: data.accessToken,
          isLoggedIn: true,
        });
        originalRequest.headers["Authorization"] = `Bearer ${data.accessToken}`;
        // 다시 설정해주고 원래 요청으로 보내주기
        return axiosInstance(originalRequest);
      } catch (err) {
        console.log(err);
      }
    }
  }
);

4. 새로고침하면 전역 상태로 관리하던 액세스 토큰이 날라가는 문제

  • 리프레시 토큰으로 액세스 토큰 다시 받아오기
  • App.tsx에서 useEffect를 이용해 첫 렌더링 시, 토큰 발급하는 api 호출

5. 리프레시 토큰을 API 요청에 함께 보내는 방법

  • withCredentials : HTTP 요청에서 쿠키, 인증 헤더, 도는 기타 자격 증명을 포함하도록 설정하는 옵션
    • axios에서 withCredentials를 true로 설정하면, 클라이언트와 서버 간의 요청에 자격 증명 포함 가능
    • 자격 증명을 필요로 하는 경우에만 true로 설정 (리프레시 토큰 받을 때, 보낼 때)
  • 이 방식 말고
    • Authorization 헤더에 토큰을 담아 전송하는 방식도 있음

6. Private Route 구현

  • 로그인 여부에 따라 유저의 접근을 제한해야 하는 경우
import { useEffect, useState } from "react";
import { Outlet, useNavigate } from "react-router";
import { useAuthStore } from "../stores/authStore";

export default function Private() {
  const navigate = useNavigate();
  const [show, setIsShow] = useState(false);
  const isLoggedIn = useAuthStore((state) => state.isLoggedIn);
  useEffect(() => {
    if (!isLoggedIn) {
      navigate("/login");
      return;
    }
    setIsShow(true);
  }, []);

  // show를 사용한 이유는 찰나의 순간 보일 수도 있기 때문에 막은 것
  return <>{show && <Outlet />}</>;
}





📌 출처

수코딩(https://www.sucoding.kr)

profile
프론트엔드를 공부하고 있는 학생입니다🐌

0개의 댓글

관련 채용 정보