iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0
Modern Web

不只是登入畫面!一起打造現代化登入系統系列 第 18

屋內安全[ 7 / 7 ]:Token 要放哪裡?LocalStorage、Cookie、Memory 的優缺點與實作方式

  • 分享至 

  • xImage
  •  

當我們拿到 Firebase 的 idToken 後,下一個問題就是 ——「要放哪裡?」
前端有三個常見選擇:

儲存方式 優點 缺點 適用情境
LocalStorage 寫法簡單、刷新不會消失 暴露在 JS 環境,容易被 XSS 盜走 練習、後台系統、開發階段
Cookie(HttpOnly) 可防止 JS 存取,安全性高 須後端設定、需配合 SameSite & Secure 正式環境、敏感資料
Memory(React State / Context) 不落地、不怕 XSS 一刷新就消失,需要 Refresh Token SPA + 自動刷新 Token

我們這邊會先用最容易上手的方式 👉 LocalStorage 實作
後面再告訴你為什麼正式環境建議改用 Cookie。


LocalStorage 存取 Token(開發最快)

  • 儲存 Token
export const saveToken = (token) => {
  localStorage.setItem("idToken", token);
};
  • 讀取 Token
export const getToken = () => {
  return localStorage.getItem("idToken");
};
  • 移除 Token(登出用)
export const removeToken = () => {
  localStorage.removeItem("idToken");
};

放進登入流程(只示範概念)

import { saveToken } from "./utils/tokenStorage";
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";

export const login = async (email, password) => {
  const auth = getAuth();
  const result = await signInWithEmailAndPassword(auth, email, password);
  const token = await result.user.getIdToken();
  saveToken(token);
  return result.user;
};

丟到 /auth/verify 時從 localStorage 撈

export const verifyWithStoredToken = async () => {
  const token = getToken();
  if (!token) throw new Error("沒有 Token");

  const res = await fetch("/auth/verify", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ idToken: token }),
  });

  if (!res.ok) {
    removeToken(); // 避免無效 Token 留著
    throw new Error("驗證失敗");
  }

  return res.json();
};

LocalStorage 的缺點(正式環境不推薦)

  • ❌ 容易被 XSS 拿走 Token(任何能執行 JS 的漏洞都能讀到它)
  • ❌ 不能加 HttpOnly、不能防止惡意腳本偷走
  • ❌ 如果被盜,就能冒用你的身分一直打 API

所以在「開發階段」可以用、但上線務必要換方式。


上一篇
屋內安全[ 6 / 7 ]:AuthContext + Protected Route 實作
系列文
不只是登入畫面!一起打造現代化登入系統18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言