iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Modern Web

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

屋內安全[ 4 / 6 ]:JWT 驗證與最小後端實作

  • 分享至 

  • xImage
  •  

在做前端登入系統時,你可能會想:「我不是已經用 Firebase Login 登入了嗎?為什麼還要搞一個後端驗證?」別急,這篇文章用最輕鬆的方式帶你理解,還會附上兩種實作方案:真後端 Express + Firebase Admin,以及MSW 模擬後端,適合想快速開發或測試的你。


為什麼 Firebase Login 之後還需要驗證 Token?

Firebase SDK 確實可以直接在前端登入,拿到 idToken,你甚至可以直接呼叫 Firebase 的服務。但如果你的應用有 自訂後端 API,就必須驗證這個 Token。原因有三個:

  1. 安全性:前端 Token 可以被竄改,如果後端不驗證,你就沒辦法保護資料。
  2. 自訂邏輯:例如使用者資料需要存在你自己的 DB,或某些操作需要角色驗證。
  3. 統一入口:讓所有前端請求都經過後端驗證,方便未來切換認證方案或加上額外權限控管。

最小可用 Express 後端(含 Firebase Admin)

安裝

npm install express firebase-admin dotenv cors

初始化
先建立 firebase-admin 的設定檔(可用 Service Account JSON):

import admin from "firebase-admin";
import dotenv from "dotenv";
dotenv.config();

admin.initializeApp({
  credential: admin.credential.cert(JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT)),
});

export default admin;

建立 server

import express from "express";
import cors from "cors";
import admin from "./firebaseAdmin.js";

const app = express();
app.use(cors());
app.use(express.json());

// 驗證 Token
app.post("/auth/verify", async (req, res) => {
  const { idToken } = req.body;
  try {
    const decodedToken = await admin.auth().verifyIdToken(idToken);
    res.json({ uid: decodedToken.uid, email: decodedToken.email });
  } catch (error) {
    res.status(401).json({ error: "Token 無效或過期" });
  }
});

// 模擬登出
app.post("/auth/logout", (req, res) => {
  // Firebase 後端不直接處理前端 Token,登出由前端清除 Token
  res.json({ message: "登出成功(前端自行清理 token)" });
});

app.listen(process.env.PORT, () => {
  console.log(`Server running on http://localhost:${process.env.PORT}`);
});

這樣你就有一個最小可用的 Firebase 驗證後端了。


MSW 模擬後端(如果不啟後端)

如果你不想啟 Express 後端,也可以用 MSW 模擬 API。
安裝 MSW

npm i -D msw

建立 handler

import { rest } from "msw";

export const handlers = [
  rest.post("/auth/verify", (req, res, ctx) => {
    const { idToken } = req.body;
    if (idToken === "fake-token") {
      return res(
        ctx.status(200),
        ctx.json({ uid: "123", email: "user@example.com" })
      );
    }
    return res(ctx.status(401), ctx.json({ error: "Token 無效或過期" }));
  }),
  rest.post("/auth/logout", (req, res, ctx) => {
    return res(ctx.status(200), ctx.json({ message: "登出成功" }));
  }),
];

接 React 使用流程

import { setupWorker } from "msw";
import { handlers } from "./handlers";

export const worker = setupWorker(...handlers);

// index.js 或 main.tsx
if (process.env.NODE_ENV === "development") {
  const { worker } = await import("./mocks/browser");
  worker.start();
}


上一篇
屋內安全[ 3 / 6 ]:Firebase Token 機制:ID Token、Refresh、自動更新與權限驗證
下一篇
屋內安全[ 4 / 6 ]:React 串接驗證流程實作
系列文
不只是登入畫面!一起打造現代化登入系統18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言