各種登入授權流程圖解
SSO、session cookie、JWT bearer 權杖、OAuth —— 每一種都畫成看得懂的圖。
我們要圖解什麼?
登入驗證之所以難懂,是因為最關鍵的步驟都「看不見」—— 它們發生在瀏覽器、你的伺服器、身分提供者之間。這篇把四種最常見的登入流程畫成循序圖(sequence diagram),讓你親眼看到:誰跟誰說話、順序是什麼、中間傳了什麼東西。
驗證(Authentication) vs 授權(Authorization)
驗證(authentication)回答的是「你是誰?」(在門口出示證件);授權(authorization)回答的是「你被允許做什麼?」(你的票能不能進 VIP 室)。底下每一種流程,都是先做一次驗證,之後每次請求再帶著「我已驗證過」的憑證。
1. Cloudflare Access SSO
SSO(Single Sign-On,單一登入)是指:你只在一個身分提供者登入一次,之後就能進到很多應用程式、不用重複登入。用 Cloudflare Access 時,Cloudflare 會擋在你的應用程式前面、把整個登入流程包辦掉 —— 你完全不用自己寫驗證程式碼。登入後,Cloudflare 會給瀏覽器一個「已簽章的 cookie」,讓你的應用程式可以信任。
為什麼團隊愛用它
你的應用程式永遠看不到密碼,你也不用寫任何登入邏輯。Cloudflare 負責執行政策(誰能進),只把「已驗證」的請求轉給你。拿來保護內部儀表板、後台管理頁面最適合。
2. Session cookie 登入
session(連線階段)是伺服器對「某一位已登入訪客」的記憶。登入成功後,伺服器會存一筆 session 紀錄(這裡放在 Workers KV),並發給瀏覽器一個 cookie,裡面只放一串隨機的 session id。瀏覽器之後每次請求都會自動帶上這個 cookie,伺服器再用這個 id 去查出「你是誰」。這是傳統伺服器渲染網頁最經典的流程。
把 cookie 顧好
把 cookie 設成 HttpOnly(JavaScript 讀不到)、Secure(只走 HTTPS)、SameSite(降低 CSRF 跨站偽造請求)。並給 KV 的 session 設一個 TTL(存活時間)讓它自動過期。cookie 本身不放任何使用者資料 —— 它只是一把查表用的鑰匙。
3. JWT bearer 權杖 API 驗證
JWT(JSON Web Token)是一段「已簽章的字串」,裡面帶有 claims(聲明),例如 user id 和到期時間。因為它是用密鑰簽出來的,伺服器不用存任何東西就能信任它 —— 只要驗章就好。用戶端會把它放在 Authorization 標頭裡當作 bearer(持有者)權杖送出,意思是「誰持有這個權杖,誰就能進」。這是 API、單頁應用(SPA)、手機 App 最常用的流程。
export default {
async fetch(req, env) {
const header = req.headers.get("Authorization") || "";
const [scheme, token] = header.split(" ");
if (scheme !== "Bearer" || !token) {
return new Response("Missing bearer token", { status: 401 });
}
const valid = await verifyJWT(token, env.JWT_SECRET);
if (!valid) return new Response("Invalid token", { status: 401 });
return Response.json({ ok: true, message: "Welcome back!" });
}
};
// Verify an HS256 JWT signature with the Web Crypto API
async function verifyJWT(token, secret) {
const [head, body, sig] = token.split(".");
if (!head || !body || !sig) return false;
const key = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["verify"]
);
const signed = new TextEncoder().encode(head + "." + body);
const bytes = Uint8Array.from(
atob(sig.replace(/-/g, "+").replace(/_/g, "/")),
(c) => c.charCodeAt(0)
);
return crypto.subtle.verify("HMAC", key, bytes, signed);
}光驗簽章還不夠
簽章驗過之後,還要解開 payload(內容),如果 exp(到期時間)已經過了就拒絕。權杖要設短效期(幾分鐘到一小時),而密鑰要放在 Worker secret(密鑰)裡,絕對不要寫死在程式碼。
4. OAuth 第三方登入
OAuth 讓使用者用「他原本就有的帳號」(例如 Google、GitHub)登入,而不用把密碼交給你的應用程式。你的應用程式把使用者導向提供者,使用者按下同意,提供者再帶著一組短效的「授權碼(code)」導回來。接著你的應用程式在伺服器端用這組 code 去換取存取權杖(access token)。底下這種「authorization code(授權碼)」流程,就是最安全、最推薦的做法。
瀏覽器拿到的是 code,不是 token
瀏覽器自始至終只看得到一次性的 code;真正的權杖是伺服器對伺服器去拿的,所以不會外洩。client secret(用戶端密鑰)要留在伺服器,並用 state 參數加上 PKCE 來擋掉偽造的 callback(回呼)。
什麼時候用哪一種?
Access SSO
給自己團隊用的內部工具。不用寫登入程式碼 —— Cloudflare 替你守門,並決定誰能進。
Session cookie
傳統、伺服器渲染的網站,而且只有瀏覽器這一種用戶端。觀念簡單,也容易隨時讓登入失效。
JWT bearer
API、單頁應用、手機 App,以及服務對服務的呼叫。無狀態(stateless)—— 不需要 session 儲存區。
OAuth
讓使用者用 Google、GitHub 等帳號登入 —— 或在取得他們同意後,存取他們在那些服務上的資料。
重點術語
SSO 單一登入
Single Sign-On:登入一次,就能進到很多應用程式、不用重複登入。
Session 連線階段
伺服器對「某一位已登入訪客」的紀錄,通常存在 KV 這類儲存區。
Cookie
瀏覽器存起來、每次請求都會自動再送出的一小段值 —— 這裡用來帶 session id。
JWT
一個已簽章的 JSON 權杖,帶有 claims(user id、到期時間),伺服器不用查表就能信任。
Bearer 權杖
用 'Authorization: Bearer <token>' 送出。誰持有它,就被當作已獲授權。
OAuth
一套標準,讓你用別的服務的帳號登入,而不用把密碼分享出去。
小提示與陷阱
一律走 HTTPS
cookie 和 bearer 權杖就像鑰匙 —— 誰複製到就能假冒使用者。HTTPS 能讓它們在傳輸途中不被偷看,而且只要網域掛在 Cloudflare 代理後面,預設就已開啟。
- 能避免就別把原始 JWT 或 session id 存在 localStorage —— 用 HttpOnly cookie 對 XSS(跨站腳本)更安全。
- 在伺服器端「同時」驗證 JWT 的簽章「和」到期時間;絕對不要只信 payload 內容。
- 純內部工具的話,Cloudflare Access 常常能取代上面這一切,完全免寫驗證程式碼。
- 在登入表單加上 Turnstile,在機器人碰到你的密碼檢查之前就先擋掉。
- 給 session 和權杖設短效期,並做一個真正的登出 —— 會刪掉伺服器端的 session。