┌──────────────────────────────────────────────┐
│ 호출: setToken(newToken, expiryMs) │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────┐
│ window 존재 확인 (브라우저?) │
└──────────────────────────┘
│ │
┌──────▼──────┐ ┌─────▼──────┐
│ ✅ 클라이언트(CSR) │ │ 🌐 서버(SSR) │
└──────────────┘ └───────────┘
│ │
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────────────┐
│ newToken 존재 확인 │ │ localStorage 없음 │
└──────────────────┘ │ → set 상태만 변경 │
│ │ │ (token, isAuthenticated) │
│ │ └────────────────────────────┘
│ │
│ └───❌ newToken 없음 (로그아웃)─────────────┐
│ │
▼ ▼
┌────────────────────────────┐ ┌────────────────────────────┐
│ 1. 토큰 저장: localStorage │ │ 1. localStorage 비우기 │
│ ("access_token") │ │ ("access_token") │
│ 2. 만료시각 계산 │ │ 2. "token_expiry" 제거 │
│ (expiryMs || 1시간) │ │ 3. 상태 초기화 │
│ 3. 만료시각 저장 │ │ (isAuthenticated: false)│
│ ("token_expiry") │ └────────────────────────────┘
│ 4. 상태 업데이트 │
│ (isAuthenticated: true) │
└────────────────────────────┘
setToken: (newToken, expiryMs) => {
if (typeof window !== 'undefined') {
if (newToken) {
// 토큰 기록
localStorage.setItem('access_token', newToken);
// 만료시각 기록(현재시각 + 주어진 ms). 기본: 1시간
const expiry =
typeof expiryMs === 'number' ? Date.now() + expiryMs : Date.now() + 60 * 60 * 1000;
localStorage.setItem('token_expiry', String(expiry));
set({ token: newToken, tokenExpiry: expiry, isAuthenticated: true });
} else {
// 토큰 제거
localStorage.removeItem('access_token');
localStorage.removeItem('token_expiry');
set({ token: null, tokenExpiry: null, isAuthenticated: false });
}
} else {
// SSR 안전 처리
set({ token: newToken, tokenExpiry: null, isAuthenticated: !!newToken });
}
🧩 코드의 역할 요약
👉 setToken 함수는 “로그인 토큰을 저장하거나 지우는 역할”을 합니다.
즉, 로그인하면 토큰 저장, 로그아웃하면 토큰 삭제!
🔍 한 줄씩 쉬운 해석
setToken: (newToken, expiryMs) => {
- newToken: 새로 받은 로그인 토큰 (JWT 등)
- expiryMs: 이 토큰이 얼마나 유효한지(밀리초 단위, 예: 1시간 = 3600000)
if (typeof window !== 'undefined') {
- “브라우저 환경인지” 확인하는 코드예요.
- SSR(Server Side Rendering)일 때는 window가 없기 때문에,
이 조건은 ‘클라이언트일 때만 실행’ 하도록 분기하는 거예요.
🟢 ① 클라이언트(CSR) 환경일 때
if (newToken) {
- 로그인 성공 시 (토큰이 있을 때) 실행됩니다.
🧱 토큰 기록
localStorage.setItem('access_token', newToken);
👉 브라우저 localStorage에 로그인 토큰 저장
(즉, 새로고침해도 토큰 유지 가능)
⏰ 만료시각 계산
const expiry = typeof expiryMs === 'number' ? Date.now() + expiryMs : Date.now() + 60 * 60 * 1000;
👉 현재 시각(Date.now())에
expiryMs만큼 더해서 만료 시점을 계산
(만약 값이 없으면 기본 1시간 후)
📦 만료시각도 저장
localStorage.setItem('token_expiry', String(expiry));
👉 토큰이 언제 만료될지도 함께 저장
✅ 상태 업데이트
set({ token: newToken, tokenExpiry: expiry, isAuthenticated: true });
👉 Zustand 같은 전역 상태에 로그인 상태를 반영
(isAuthenticated: true = 로그인 됨)
🔴 ② 로그아웃 시 (토큰이 없을 때)
} else { localStorage.removeItem('access_token');
localStorage.removeItem('token_expiry');
set({ token: null, tokenExpiry: null, isAuthenticated: false }); }
👉 저장된 토큰과 만료시각을 완전히 지우고
로그인 상태를 “false”로 초기화합니다.
⚙️ ③ 서버(SSR) 환경일 때
} else {
// SSR 안전 처리
set({ token: newToken, tokenExpiry: null, isAuthenticated: !!newToken }); }
- 여기선 localStorage가 없기 때문에
(Node.js 서버에는 브라우저 저장소가 없어요!) - 단순히 상태만 바꿔줍니다.
- !!newToken은 “토큰이 있으면 true, 없으면 false”라는 의미예요.
🧠 한 줄 요약 버전
- 브라우저라면 localStorage에 토큰과 만료시각 저장
- 서버라면 localStorage 접근 없이 안전하게 상태만 변경
- 로그인/로그아웃 모두 이 함수 하나로 처리됨
'Sprint_FESI11 > Project' 카테고리의 다른 글
| 웹이 SSR(서버가 코드를 해석해서 HTML을 만들어주는 구조) 를 유지하는 존재 이유 (0) | 2025.10.16 |
|---|---|
| JSP vs ASP vs SSR (0) | 2025.10.16 |
| 토큰 기반 렌더링 흐름 (0) | 2025.10.16 |
| 서버는 렌더링만 하는데, 왜 토큰을 가지고 있지? (0) | 2025.10.16 |
| SSR 환경에서 단순히 상태만 바꿔준다는 것의 의미 (0) | 2025.10.16 |