Musta React

11/26 (Tue) HTTP 통신과 Ajax & 리액트 라우터가 제공하는 훅

taytay 2024. 11. 26. 17:23

1. 세션 스토리지 방식 (Session Storage 방식)

세션 스토리지는 서버가 클라이언트 상태를 관리하는 전통적인 방법입니다.

작동 원리

  1. 클라이언트가 서버에 로그인 요청을 보냄.
  2. 서버는 사용자를 인증한 후, 고유한 세션 ID를 생성.
  3. 서버는 생성된 세션 ID와 함께 클라이언트의 로그인 상태를 서버의 메모리 또는 데이터베이스에 저장.
    • 예: 세션 ID와 사용자 정보를 매핑.
  4. 클라이언트는 세션 ID를 쿠키에 저장하고, 이후 요청마다 이 세션 ID를 함께 전송.
  5. 서버는 요청이 올 때마다 쿠키에 담긴 세션 ID를 확인하고, 서버에 저장된 세션 정보를 참고하여 요청을 처리.

특징

  • 서버가 클라이언트 상태를 직접 관리하기 때문에 **상태를 유지(stateful)**할 수 있음.
  • 세션 데이터는 서버 메모리 또는 데이터베이스에 저장되며, 클라이언트가 로그아웃하거나 세션이 만료되면 삭제됨.

장점

  • 보안이 상대적으로 강함: 중요한 데이터를 서버에서 관리하므로, 클라이언트 측에서 데이터를 위조하기 어려움.
  • 세션 데이터를 서버에서 직접 관리하므로, 사용자 상태와 관련된 작업이 용이함.

단점

  • 서버 부하 증가: 사용자가 많아질수록, 서버가 관리해야 하는 세션 데이터가 늘어나 서버 리소스를 소모.
  • 서버 확장이 어려움: 여러 서버가 사용될 경우, 세션 데이터를 모든 서버에서 공유하거나 별도의 중앙 저장소를 사용해야 함.

 

2. JWT 방식

JWT(JSON Web Token)는 클라이언트가 상태 정보를 관리하는 방법입니다.

작동 원리

  1. 클라이언트가 서버에 로그인 요청을 보냄.
  2. 서버는 사용자를 인증한 후, 해당 사용자 정보를 포함한 JWT 토큰을 생성.
    • 토큰에는 Header, Payload, Signature로 이루어진 정보가 포함됨.
  3. 생성된 JWT를 클라이언트에게 전달하며, 클라이언트는 이 JWT로컬 스토리지(Local Storage) 또는 쿠키에 저장.
  4. 이후 클라이언트는 요청마다 JWT를 서버에 전달.
  5. 서버는 클라이언트가 보낸 JWT의 **서명(Signature)**을 확인하여 토큰이 유효한지 검증한 후 요청을 처리.

특징

  • 서버가 클라이언트 상태를 저장하지 않음(무상태, stateless). → 클라이언트가 직접 JWT를 서버에 전달
  • JWT는 클라이언트 측에서 상태를 유지하므로, 서버의 부하가 줄어듦.
  • 서버는 JWT의 서명만 검증하며 상태 정보를 확인함.

장점

  • 서버 확장이 쉬움: 상태 정보가 서버에 저장되지 않으므로, 어떤 서버든 동일한 키를 사용해 토큰을 검증할 수 있음.
  • 네트워크 비용 감소: 요청마다 서버가 별도의 상태 조회 없이 JWT만 검증하면 됨.
  • 무상태(stateless): REST API 설계 원칙에 부합.

 

REST API (= Representational State Transfer)

: 네트워크 상에서 자원을 정의하고 자원에 대한 주소(URL)를 지정해 이를 전송하는 아키텍처 스타일

단점

  • 보안 문제: JWT 자체가 클라이언트에 저장되므로, 노출될 경우 보안 위협 발생.
    • 민감한 데이터를 payload에 저장하면 안 됨.
    • HTTPS를 사용해 전송 암호화 필요. -> client-id를 보내야하는 이유??
  • 토큰 관리 어려움: JWT는 기본적으로 만료되기 전까지 유효하며, 강제 로그아웃 등의 작업이 어려움.
    • 이를 보완하기 위해 리프레시 토큰 사용.

 

세션 방식 vs JWT 방식 비교

상태 관리 서버가 상태 관리 (stateful) 클라이언트가 상태 관리 (stateless)
서버 부담 세션 저장소 관리 필요 (부하 증가) 서버 부담 적음
보안 서버에서 직접 관리 (보안 강함) 클라이언트에 토큰 저장 (노출 시 보안 문제 발생 가능)
확장성 서버 확장 어려움 서버 확장 용이
만료 관리 서버에서 세션 만료 시간 관리 JWT 자체에 만료 시간 포함
사용 사례 전통적인 웹 애플리케이션 SPA, REST API 기반 애플리케이션

 

 

간단한 방법

JWT의 간단한 특징

  • 서버는 JWT를 검증만 하므로 클라이언트 상태를 저장하지 않아도 됨.
  • 클라이언트는 자신이 받은 JWT를 직접 저장하고 요청 시마다 보내기만 하면 됨.
  • 서버 입장에서 "토큰의 유효성 검증"만으로 모든 작업이 처리되므로 상대적으로 구현이 간단.

세션 방식의 간단한 특징

  • 클라이언트는 세션 ID만 보관.
  • 서버가 모든 상태 정보를 직접 관리하므로 클라이언트에서 특별한 데이터 관리 필요 없음.

JWT와 세션 방식 중 어떤 것을 선택할지는 보안, 확장성, 서버 부하 등 시스템의 요구 사항에 따라 결정하면 됩니다.

 

세션 방식이 완전히 사라진 것은 아니며, 여전히 적합한 상황에서 사용되고 있습니다.
JWT는 현대적인 요구 사항에 적합한 간단하고 효율적인 방식으로, 특히 REST API와 클라우드 환경에서 선호됩니다.
하지만 보안과 사용자 상태 관리가 중요한 전통적인 웹 애플리케이션에서는 여전히 세션 방식이 널리 사용되고 있습니다.

따라서 둘 중 어떤 방식을 선택할지는 프로젝트의 특성과 요구 사항에 따라 다릅니다. JWT는 새로운 방식이지, 세션 방식의 완전한 대체가 아닙니다.

 

왜 많은 곳에서 JWT를 사용하는가?

  1. 확장성 (Scalability)
    • 세션 방식은 서버가 클라이언트의 상태를 저장하기 때문에, 여러 서버(또는 분산 환경)에서 동일한 세션 정보를 공유해야 하는 문제가 있습니다.
    • JWT는 상태를 서버가 저장하지 않고, 클라이언트가 가지고 있기 때문에, 여러 서버에서 처리해야 할 경우(예: 클라우드 환경) 확장성이 뛰어납니다.
  2. REST API와의 적합성
    • REST API는 무상태(stateless) 프로토콜을 지향합니다.
    • JWT는 클라이언트 측에서 상태를 유지하므로, RESTful 설계와 자연스럽게 잘 맞습니다.
  3. 현대적인 클라이언트 중심 애플리케이션
    • SPA(Single Page Application)나 모바일 애플리케이션에서는 클라이언트와 서버가 독립적으로 동작하는 경우가 많습니다.
    • 이 경우, 클라이언트가 JWT를 통해 인증 상태를 관리하는 방식이 간단하고 효율적입니다.

 

세션 방식은 더 이상 사용되지 않는가?

아직도 세션 방식이 적합한 경우

  1. 보안이 매우 중요한 경우
    • 세션 방식은 서버가 직접 클라이언트의 상태를 관리하므로, 보안이 강화됩니다.
    • 민감한 정보를 클라이언트에 노출하지 않고 서버에서 처리하므로, 중요한 금융 애플리케이션(인터넷 뱅킹)에서 주로 사용됩니다.
  2. 사용자 상태를 지속적으로 관리해야 하는 경우
    • 예를 들어, 사용자의 쇼핑 카트 상태나 특정 워크플로우를 유지해야 할 때 세션 방식이 더 적합할 수 있습니다.
    • 서버에서 상태를 관리하므로 클라이언트가 따로 신경 쓸 필요가 없습니다.
  3. 서버 부하가 적은 환경
    • 세션 방식은 서버의 메모리나 스토리지에 상태를 저장해야 하므로, 사용자가 많아질수록 서버 부하가 증가합니다.
    • 하지만, 소규모 애플리케이션에서는 서버 부하 문제가 크지 않으므로, 여전히 세션 방식이 실용적입니다.

bearerToken이라는 걸 이용해서 인증하자
니(클라이언트)가 이걸 저장하고 있다가 나(서버)한테 HTTP 요청보낼때 요청헤더에 넣어서 보내줘
그럼 내가 authorization 헤더값을 꺼내서 토큰을 꺼내볼테니까 

JSON webtoken -> decoding -> 어떤 알고리즘으로 만들어져있는지에 대한 정보 나옴
payload: 서버가 어떤 사용자가 로그인 했는지 알 수 있음.


💥 이 JWT 토큰은 서버에서 키값을 가지고 만든 거기 때문에 역으로 payload에서 id를 바꿔서 토큰을 바꿔봤자 그 토큰은 원본 토큰과 결론적으로 다른 키값을 가지고 있기 때문에 서버에서 인증 실패난다

=> 세션 스토리지 방법처럼 서버가 직접 클라이언트 정보를 저장하지 않아도, 클라이언트가 로그인할 때마다 JWT토큰을 보내주면 서버가 자기가 갖고 있는 키값을 가지고 식별(매칭)했을 때, 성공하면 ok, 매칭 안되면 빡구~!

 


리액트 라우터가 제공하는 Hook

useRouteError

에러처리 전용 라우트에 제공되는 Error 객체를 반환

import { useRouteError } from "react-router-dom";

function ErrorPage(){
  const err = useRouteError();
  const message = err.status === 404 ? '존재하지 않는 페이지입니다.' : '예상하지 못한 에러가 발생했습니다.';
  return (
    <div id="main">
      <div className="todo">
        <h2>에러 발생</h2>
        <p>{ message }</p>
      </div>
    </div>
  );
}

export default ErrorPage;

 

 

useParams

URI 파라미터 값을 꺼낼 때 사용

 

- Router 설정

{ 
  path: 'list/:_id',
  element: <TodoDetail />
}

 

- TodoDetail.jsx

const params = useParems();
const _id = params._id;
// 또는
const { _id } = useParams();

 

 

useNavigate

페이지를 이동할 수 있는 navigate 함수 반환

const navigate = useNavigate();
// navigate(to, options)
navigate('/', { state: { from: '/list' } }); // history.pushState({ from: '/list' }, '', '/')
navigate('/list?keyword=hello', { replace: true }); // history.replaceState(null, '', '/list?keyword=hello')
navigate('..', { relative: 'path' }); // 상대경로 지정

 

 

useOutletContext

중첩 라우팅에서 부모가 Outlet 컴포넌트의 context 속성으로 전달한 값을 접근

  • 부모 컴포넌트
<Outlet context={ itemList } />

 

  • 자식 컴포넌트
const itemList = useOutletContext();