微服務架構將單體應用拆分為眾多獨立服務後,安全認證機制面臨根本性的轉變:傳統基於 Session-Cookie 的有狀態認證不再適用,取而代之的是以 Token 為核心的授權框架。本章涵蓋以下主題:

  • 微服務安全挑戰
  • OAuth2 核心概念與四種授權流程
  • JWT 機制
  • OpenID Connect
  • 生產環境的 Token 校驗架構方案

微服務安全挑戰#

從單體到微服務的安全演進#

在傳統單體架構中,安全認證相對簡單:使用者登入後,伺服器建立 Session,瀏覽器透過 Cookie 維持狀態。然而在微服務架構下,這套模式面臨三大核心挑戰:

挑戰領域問題描述
開放系統授權第三方應用需要存取受保護資源(如聯合登入、開放 API),傳統的帳密共享方式極不安全
多樣化用戶端接入端不再僅限於瀏覽器,還包括 SPA、Mobile App、伺服器端應用等多種形態
服務間認證服務拆分後,服務與服務之間也需要認證與鑑權,Session 機制無法跨服務共享

微服務環境下,安全機制從「使用者名稱/密碼 + Session」轉變為依賴獨立的 Authorization Server(授權伺服器),核心技術從有狀態 Session 轉變為 無狀態的 Token 授權機制

傳統授權方式的侷限#

在 OAuth2 出現之前,讓第三方應用存取受保護資源的方式都存在明顯缺陷:

  • 帳密複製:將使用者帳號密碼直接交給第三方,權限過大且無法保證不被濫用
  • 通用開發者金鑰:合作夥伴共享萬能金鑰,一旦洩露所有資源都面臨風險
  • 特殊令牌:方向正確但缺乏標準化,令牌的頒發、管理、吊銷都無統一規範

將使用者帳號密碼直接交給不受信的第三方應用,是開放系統授權中必須避免的反模式。OAuth2 正是為了解決這個問題而誕生。

OAuth2 核心概念#

定義與本質#

OAuth 2.0 是一個用於 REST API 的代理授權框架(Delegated Authorization Framework),定義於 RFC 6749。其核心在於 Token(令牌)——在不暴露使用者帳號密碼的前提下,使第三方應用能夠獲取對使用者資料的有限存取權限。

核心概念比喻:僕從鑰匙(Valet Key)

OAuth2 的 Token 可比喻為高級轎車的僕從鑰匙

  • 常規鑰匙(Master Key):擁有完全權限(相當於使用者帳號密碼)
  • 僕從鑰匙(Token):只能用來開車(有限權限),不能打開後備箱(保護隱私),可能限制行駛里程(Scope/有效期限制)

你不需要把所有權限都交給泊車員,只需給他一把「剛好夠用」的鑰匙。

四大核心角色#

flowchart TB
    RO["Resource Owner<br/>資源擁有者(使用者)"]
    C["Client<br/>客戶應用(第三方)"]
    AS["Authorization Server<br/>授權伺服器"]
    RS["Resource Server<br/>資源伺服器"]

    RO -->|授權同意| AS
    C -->|1. 請求授權| AS
    AS -->|2. 頒發 Token| C
    C -->|3. 攜帶 Token 存取| RS
    RS -->|4. 校驗 Token 後回傳資料| C

    style AS fill:#fff3e0
    style RS fill:#e8f5e9
角色說明範例
Resource Owner資料的擁有者(使用者本人)你在雲端硬碟上的照片,你是擁有者
Client需要存取受保護資源的第三方應用雲端沖印服務
Authorization Server負責驗證身分、頒發與管理令牌授權伺服器
Resource Server託管受保護資源的伺服器Google Photos API

關鍵術語#

術語說明
Client CredentialsClient ID + Client Secret,用戶端在授權伺服器註冊後的「身分證」
Access Token短期有效的存取憑證,用於直接存取受保護資源
Refresh Token長期有效的重新整理憑證,用於在 Access Token 過期後換取新 Token
Scope權限的細粒度控制,如「只讀」、「讀寫」等
Authorization Code中間狀態的臨時憑證,用於換取 Access Token

令牌的兩種形態#

類型別名特性校驗方式
透明令牌Reference Token(引用令牌)隨機字串,不包含業務資訊必須回調授權伺服器校驗
自包含令牌Value Token(值令牌)內部攜帶完整資訊(如 JWT)可在本地校驗

四種授權流程#

授權碼模式(Authorization Code Flow)#

最複雜、最安全,也是應用最廣泛的模式。引入「授權碼」中間層,避免 Access Token 直接暴露在瀏覽器端。

sequenceDiagram
    participant U as 使用者(瀏覽器)
    participant C as 用戶端(後端)
    participant AS as 授權伺服器

    U->>C: 1. 發起請求
    C->>U: 2. 重定向至授權伺服器
    U->>AS: 3. 登入認證 + 授權同意
    AS->>U: 4. 重定向回 Client(攜帶授權碼)
    U->>C: 5. 傳遞授權碼
    C->>AS: 6. 後端渠道:用授權碼換取 Token
    AS->>C: 7. 返回 Access Token(+ Refresh Token)
  • 適用場景:有後端伺服器的 Web 應用
  • 安全性:最高,Token 不經過瀏覽器,僅在 Client 後端與授權伺服器間流轉

簡化模式(Implicit Flow)#

省去授權碼交換,Access Token 直接通過 URL Fragment 返回給瀏覽器。

  • 適用場景:無後端伺服器的 SPA
  • 安全性:較弱,Token 暴露在瀏覽器端

Implicit Flow 在 OAuth 2.1 草案中已被不推薦使用。現代最佳實踐傾向於使用**授權碼模式 + PKCE(Proof Key for Code Exchange)**來取代簡化模式。

密碼模式(Resource Owner Password Credentials Flow)#

使用者直接將帳號密碼提供給用戶端,用戶端再向授權伺服器換取 Token。

  • 適用場景:僅限高度信任的第一方應用(如公司自家 App 存取自家 API)
  • 安全性:使用者密碼暴露給用戶端,僅適用於同一信任域

用戶端模式(Client Credentials Flow)#

最簡單的模式,完全不需要使用者參與。用戶端直接以自身的 Client ID 和 Secret 獲取 Token。

  • 適用場景:機器對機器(M2M)通訊,如微服務間呼叫、CI/CD 工具
  • 安全性:Token 代表用戶端自身的權限,而非某個具體使用者

選型決策樹#

flowchart TD
    START["開始選型"] --> Q1{"令牌擁有者是誰?"}
    Q1 -->|機器| CC["用戶端模式<br/>Client Credentials"]
    Q1 -->|使用者| Q2{"用戶端類型?"}

    Q2 -->|Web 伺服器端應用| AC1["授權碼模式<br/>Authorization Code"]
    Q2 -->|原生 App / SPA| Q3{"開發方關係?"}

    Q3 -->|第一方(內部開發)| PW["密碼模式<br/>Password Credentials"]
    Q3 -->|第三方| Q4{"應用類型?"}

    Q4 -->|原生 App| AC2["授權碼模式 + PKCE"]
    Q4 -->|SPA| AC3["授權碼模式 + PKCE<br/>(取代 Implicit)"]

    style CC fill:#e8f5e9
    style AC1 fill:#e3f2fd
    style AC2 fill:#e3f2fd
    style AC3 fill:#e3f2fd
    style PW fill:#fff3e0

快速選型原則

  • 有後端的 Web 應用 -> 授權碼模式
  • SPA 或 Mobile App -> 授權碼模式 + PKCE
  • 內部信任的第一方應用 -> 密碼模式(但應逐步過渡到授權碼模式)
  • 服務間呼叫 / 排程任務 -> 用戶端模式

前端渠道 vs 後端渠道#

理解授權流程的關鍵在於區分兩種通訊渠道:

渠道參與角色特徵
前端渠道(Front-channel)使用者、用戶端、授權伺服器透過瀏覽器重定向,使用者可見
後端渠道(Back-channel)用戶端、授權伺服器、資源伺服器伺服器對伺服器通訊,使用者不可見

授權碼模式之所以最安全,正是因為 Token 的交換發生在後端渠道。

OAuth2 安全風險防護#

OAuth2 協議的初衷是解決授權與安全問題,但在實際實作中若設定不當,仍存在嚴重的安全風險。以下是架構師在設計 OAuth2 系統時必須落實的防護措施。

核心防護原則#

防護措施說明
強制使用 HTTPSClient、Authorization Server、Resource Server 之間的通訊必須全程加密,防止 Token 在傳輸過程中被竊聽
保護 Client Secret必須盡最大努力防止用戶端密碼洩露。對於無法保守秘密的公開用戶端(SPA、Mobile),應使用 PKCE 替代
嚴格驗證 Redirect URI註冊 Client 時必須明確指定合法的重定向 URL,授權伺服器收到請求時必須嚴格比對,防止授權碼或 Token 被重定向至惡意站點
強制使用 state 參數防止 CSRF 攻擊與 Token 劫持的關鍵手段(詳見下方)
Token 綁定針對進階攻擊場景,可將 Token 請求與用戶端的授權方式進行綁定,減輕 Token 被劫持的風險

CSRF 攻擊與 state 參數防禦#

OAuth2 流程中最典型的安全風險是跨站點請求偽造(CSRF)。攻擊者可利用自己的合法授權碼誘導受害者完成授權流程,導致受害者的操作(如存款、上傳資料)實際上綁定到攻擊者的帳號。

sequenceDiagram
    participant A as 攻擊者
    participant AS as 授權伺服器
    participant V as 受害者(已登入)
    participant C as 用戶端應用

    A->>AS: 1. 以自己帳號登入並授權
    AS->>A: 2. 返回授權碼(綁定攻擊者身分)
    Note over A: 3. 攔截授權碼,不讓流程完成
    A->>V: 4. 發送偽造回調連結(含攻擊者授權碼)
    V->>C: 5. 點擊連結,觸發授權碼交換
    C->>AS: 6. 用攻擊者的授權碼換取 Token
    AS->>C: 7. 返回攻擊者的 Token
    Note over C: 受害者的後續操作<br/>都綁定了攻擊者身分

state 參數的防禦機制

  • 用戶端在發起授權請求時生成一個隨機的 state 值,並儲存於 Session 中
  • 授權伺服器在回調時原封不動地返回 state
  • 用戶端校驗回傳的 state 是否與 Session 中的一致
  • 攻擊者構造的偽造連結因缺少正確的 state,將被用戶端拒絕

缺乏 state 參數校驗的用戶端無法區分授權碼是由使用者自己發起的,還是由外部惡意連結注入的。務必確保所有 OAuth2 用戶端在請求授權碼時帶上 state 參數,並在回調時進行嚴格校驗。

JWT(JSON Web Token)#

結構解析#

JWT 是一種標準化的自包含令牌,由三個部分組成,以 . 連接:

Header.Claims.Signature
flowchart LR
    subgraph JWT["JWT 結構"]
        H["Header<br/>演算法 + 類型<br/><code>alg: HS256</code>"]
        C["Claims<br/>使用者資訊 + 後設資料<br/><code>sub, exp, aud, iss</code>"]
        S["Signature<br/>防篡改簽章<br/><code>HMAC(H+C, secret)</code>"]
    end

    H --- C --- S

    style H fill:#e3f2fd
    style C fill:#fff3e0
    style S fill:#e8f5e9

Header(頭部)

  • typ:令牌類型(JWT)
  • alg:簽名演算法(如 HS256、RS256)

Claims(宣告/載荷)

欄位全稱說明
issIssuer頒發者
expExpiration Time過期時間
audAudience預期接收者
subSubject主題(如使用者 ID)
iatIssued At頒發時間

Signature(簽名)

  • 使用密鑰對 Header + Claims 進行簽名,確保內容未被篡改
  • 只有持有密鑰的授權伺服器才能簽發有效 Token

簽名是 JWT 安全性的基石。沒有簽名,任何人都可以偽造 JSON 宣告自己擁有管理員權限。資源伺服器在驗證 JWT 時,首先驗簽,再檢查 aud 是否匹配、exp 是否過期。

JWT 的校驗邏輯#

資源伺服器收到 JWT 後的處理流程:

  1. 驗證簽名:確認由信任的授權伺服器頒發
  2. 檢查過期時間:確認 exp 未過期
  3. 檢查 Audience:確認 aud 與當前服務匹配
  4. 提取權限資訊:從 Claims 中讀取使用者角色與 Scope

JWT 的核心優勢在於去中心化校驗。資源伺服器可以在本地完成所有合法性校驗,完全不需要與授權伺服器進行網路通訊,這在高併發場景下具有顯著的效能優勢。

Reference Token vs JWT 對比#

比較維度Reference TokenJWT(Self-contained Token)
內容隨機字串,不含資訊包含完整使用者與權限資訊
校驗方式回調授權伺服器 Introspection 端點本地驗簽即可
效能每次校驗需網路請求本地校驗,無網路開銷
即時吊銷支援(授權伺服器可直接失效)不支援(須等待自然過期)
Token 大小較大(攜帶完整資訊)

OpenID Connect(OIDC)#

OIDC 與 OAuth2 的關係#

OAuth2 本質上是一個**授權(Authorization)**協議,不負責驗證使用者身分。OpenID Connect 在 OAuth2 之上增加了標準化的身份認證層。

flowchart TB
    subgraph Stack["協議堆疊"]
        direction TB
        OIDC["OpenID Connect<br/>身份認證 + ID Token + UserInfo"]
        OAuth["OAuth 2.0<br/>授權流程 + Access Token"]
        JWT_Layer["JWT / JWS / JWE<br/>資料格式 + 簽名 + 加密"]
    end

    OIDC --> OAuth --> JWT_Layer

    style OIDC fill:#e3f2fd
    style OAuth fill:#fff3e0
    style JWT_Layer fill:#e8f5e9

OIDC = OAuth 2.0 + Identity + Authentication。它利用 OAuth2 作為底層基礎,明確增加了身份認證功能。

OIDC 的關鍵特徵#

特徵說明
ID Token新增的令牌類型,經過簽名,專門包含使用者身份認證資訊
UserInfo Endpoint標準化端點,可用 Token 存取以獲取額外使用者資訊
標準化 Scopes/Claimsprofileemailphone 等欄位已被標準化
會話管理支援 SSO(單點登入)場景,統一的會話管理與吊銷
用戶端發現簡化用戶端組態流程
OAuth2 vs OIDC 的核心差異
比較維度OAuth 2.0OpenID Connect
定位授權框架(Authorization)身份認證層(Authentication)
回答的問題「這個應用能做什麼?」「這個使用者是誰?」
核心 TokenAccess TokenAccess Token + ID Token
使用者資訊不提供標準化方式UserInfo Endpoint
典型場景API 授權存取聯合登入、SSO

生產環境 Token 校驗架構#

在真實的企業微服務架構中,授權伺服器需要與 API 閘道、內部微服務群緊密協作。以下是三種主流的 Token 校驗與傳遞方案。

方案一:閘道集中校驗與 Token 交換#

核心思想是將「有狀態」與「無狀態」的界線劃分在 API 閘道層。

sequenceDiagram
    participant C as 用戶端
    participant GW as API 閘道
    participant AS as 授權伺服器
    participant MS as 微服務

    C->>GW: 1. 攜帶 Access Token 請求
    GW->>AS: 2. 校驗 Access Token
    AS->>GW: 3. 校驗通過 + 使用者資訊
    Note over GW: 4. 將 Access Token<br/>交換為 JWT
    GW->>MS: 5. 攜帶 JWT 轉發請求
    Note over MS: 6. 本地驗簽 JWT<br/>無需再訪問授權伺服器
    MS->>GW: 7. 返回業務資料
    GW->>C: 8. 回傳結果

特點

  • 閘道負責集中校驗,將不透明的 Access Token 交換為自包含的 JWT
  • 後端微服務進行無狀態的本地 JWT 校驗,無需再訪問授權伺服器
  • 職責清晰:閘道外是有狀態的 Access Token,閘道內是無狀態的 JWT

方案二:全鏈路無狀態 JWT#

追求極致效能,所有校驗在本地完成。

sequenceDiagram
    participant C as 用戶端
    participant GW as API 閘道
    participant MS as 微服務

    C->>GW: 1. 攜帶加密 JWT
    Note over GW: 2. 本地解密 + 驗簽<br/>(無需遠端請求)
    GW->>MS: 3. 轉發解密後的 JWT
    Note over MS: 4. 本地解碼 + 權限填充
    MS->>GW: 5. 返回業務資料
    GW->>C: 6. 回傳結果

特點

  • 用戶端直接持有加密 JWT,閘道與微服務均在本地校驗
  • 極大降低授權伺服器壓力

全鏈路 JWT 方案最大的問題在於無法即時吊銷。若 Token 被盜或發現惡意使用者,因為閘道不回調授權伺服器,無法集中指令讓 Token 失效,只能等待 JWT 自然過期。若採用此方案,務必將 JWT 過期時間設定得非常短。

方案三:閘道 + Redis 快取(推薦)#

在方案一的基礎上引入快取層,兼顧安全性與效能。

sequenceDiagram
    participant C as 用戶端
    participant GW as API 閘道
    participant Redis as Redis 快取
    participant AS as 授權伺服器
    participant MS as 微服務

    Note over AS,Redis: 預先:頒發 Token 時<br/>同步寫入 Redis
    AS->>Redis: Token -> JWT 映射

    C->>GW: 1. 攜帶 Access Token 請求
    GW->>Redis: 2. 查詢 Token 對應的 JWT
    Redis->>GW: 3. 返回 JWT
    GW->>MS: 4. 攜帶 JWT 轉發請求
    Note over MS: 5. 本地驗簽 JWT
    MS->>GW: 6. 返回業務資料
    GW->>C: 7. 回傳結果

特點

  • 授權伺服器頒發 Token 時,將 Access Token 與對應 JWT 的映射寫入 Redis
  • 閘道直接查詢 Redis 完成校驗與 Token 轉換,不再直接請求授權伺服器
  • 支援即時吊銷(從 Redis 刪除 Token 即可)

此方案是目前生產環境中最常見的架構選擇。Redis 的高讀取效能完美契合高頻 Token 校驗場景,同時保留了閘道集中管控與後端無狀態的優點,解決了頻繁呼叫授權伺服器的效能瓶頸。

三種方案對比#

比較維度方案一:閘道集中校驗方案二:全鏈路 JWT方案三:閘道 + Redis
授權伺服器壓力高(每次請求需校驗)極低(無需校驗)低(Redis 承擔)
即時吊銷能力支援不支援支援
後端微服務複雜度低(本地驗簽)低(本地驗簽)低(本地驗簽)
整體效能中等最高
推薦程度適用於低流量場景適用於對吊銷無強需求場景生產環境推薦

生產部署最佳實踐#

授權伺服器監控#

授權伺服器是微服務安全的核心,必須建立完善的監控體系:

業務指標

指標類別監控項目
認證與授權登入次數、授權請求次數
令牌生命週期頒發數量、活躍令牌總數、吊銷次數
校驗頻率Token Introspection 呼叫 QPS
用戶端統計已註冊 OAuth Client 數量

關鍵 API 效能監控

端點重要性說明
/oauth/authorize授權介面
/oauth/token令牌頒發介面
/oauth/introspect極高令牌校驗介面(最高頻)
/oauth/revoke令牌吊銷介面

高可用與效能最佳化#

在高併發場景下,如果每個請求的 Token 校驗都直接查詢資料庫,關聯式資料庫通常無法承受。務必引入 Redis 等快取層來處理令牌校驗與存取。

  • 快取策略:引入 Redis 快取 Token 與 JWT 的映射關係,大幅提升校驗吞吐量
  • 水平擴容:授權伺服器設計為無狀態或支援叢集模式,部署多台實例實現負載均衡
  • 單點防護:避免授權伺服器成為單點故障,確保單台故障不影響整體認證服務

安全設計原則#

微服務安全設計檢查清單
原則說明
Token 短時效Access Token 有效期設定為較短(如 1 小時),降低洩露風險
Refresh Token 機制透過長效 Refresh Token 換取新的 Access Token,兼顧安全與體驗
Scope 最小權限為每個用戶端設定最小必要的存取範圍
HTTPS 強制所有 Token 傳輸必須透過 HTTPS,防止中間人攻擊
CSRF 防護所有授權請求強制使用 state 參數,回調時嚴格校驗
Redirect URI 驗證授權伺服器嚴格比對註冊的 Redirect URI,禁止開放式重定向
Client Secret 保護妥善保管用戶端密碼,公開用戶端使用 PKCE 替代
密鑰輪換定期輪換 JWT 簽名密鑰,降低密鑰洩露的影響
閘道集中認證在 API 閘道層統一處理認證,後端微服務專注業務邏輯
即時吊銷機制採用 Redis 方案確保可以即時讓 Token 失效