第十二章:API 认证模式

“在微服务时代,API 认证不再是可选项,而是每个请求的必经之路。”

        mindmap
  root((API 认证))
    认证方式
      API Key
      Bearer Token
      mTLS
      HMAC 签名
    Gateway 模式
      集中认证
      分布式认证
      Token 内省
    服务间认证
      Service Account
      Service Mesh
      SPIFFE/SPIRE
    最佳实践
      生命周期管理
      速率限制
      审计日志
    

12.1 API 认证的特殊性

API 认证与传统 Web 认证有本质区别:

维度

Web 认证

API 认证

交互方式

用户交互(浏览器)

程序化(HTTP 客户端)

状态

有状态(Session)

无状态(Token)

凭证类型

Cookie

Authorization Header

调用者

人类

人类 + 机器

频率

低(页面级)

高(API 级)

12.2 API Key 认证

最简单的 API 认证方式,适合低安全要求的场景:

from fastapi import FastAPI, Header, HTTPException

app = FastAPI()

VALID_API_KEYS = {
    "key-abc123": {"name": "Service A", "permissions": ["read"]},
    "key-def456": {"name": "Service B", "permissions": ["read", "write"]},
}

@app.get("/api/data")
async def get_data(x_api_key: str = Header(...)):
    if x_api_key not in VALID_API_KEYS:
        raise HTTPException(status_code=401, detail="Invalid API key")
    client = VALID_API_KEYS[x_api_key]
    if "read" not in client["permissions"]:
        raise HTTPException(status_code=403, detail="Insufficient permissions")
    return {"data": "sensitive information", "client": client["name"]}

API Key 的问题

  • ❌ 无过期时间(除非手动管理)

  • ❌ 无法携带用户身份信息

  • ❌ 容易泄露(日志、URL、代码仓库)

  • ❌ 无标准的轮换机制

12.3 Bearer Token 认证

使用 OAuth2 Access Token,是最推荐的 API 认证方式:

请求格式:
GET /api/resource HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt

app = FastAPI()
security = HTTPBearer()

JWKS_URL = "https://auth.example.com/.well-known/jwks.json"

async def verify_bearer_token(
    credentials: HTTPAuthorizationCredentials = Depends(security)
) -> dict:
    """验证 Bearer Token"""
    token = credentials.credentials
    try:
        # 从 JWKS 获取公钥验证
        payload = jwt.decode(
            token,
            get_public_key(token),  # 从 JWKS 获取
            algorithms=["RS256"],
            audience="my-api",
            issuer="https://auth.example.com",
        )
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

@app.get("/api/profile")
async def get_profile(user: dict = Depends(verify_bearer_token)):
    return {"user_id": user["sub"], "roles": user.get("roles", [])}

12.4 mTLS 客户端证书认证

最安全的 API 认证方式,适合服务间通信:

请求流程:
┌──────────┐                         ┌──────────┐
│  客户端   │  TLS 握手(双向证书验证) │  服务器   │
│ (带证书)  │◀────────────────────────▶│ (带证书)  │
│          │                         │          │
│          │  HTTP 请求(加密通道内)   │          │
│          │─────────────────────────▶│          │
│          │  无需额外 Token!         │ 从证书中  │
│          │                         │ 提取身份  │
└──────────┘                         └──────────┘
import httpx

# mTLS 客户端请求
async def call_service_with_mtls():
    async with httpx.AsyncClient(
        cert=("client.crt", "client.key"),  # 客户端证书
        verify="ca.crt",                     # CA 证书
    ) as client:
        response = await client.get("https://service-b:8443/api/data")
        return response.json()

12.5 HMAC 签名认证

类似 AWS Signature V4,通过对请求内容签名来验证身份和完整性:

import hmac
import hashlib
import time
from urllib.parse import urlencode

def sign_request(method: str, path: str, body: str,
                 access_key: str, secret_key: str) -> dict:
    """对 API 请求进行 HMAC 签名"""
    timestamp = str(int(time.time()))
    
    # 构造签名字符串
    string_to_sign = f"{method}\n{path}\n{timestamp}\n{hashlib.sha256(body.encode()).hexdigest()}"
    
    # 计算签名
    signature = hmac.new(
        secret_key.encode(),
        string_to_sign.encode(),
        hashlib.sha256
    ).hexdigest()
    
    return {
        "X-Access-Key": access_key,
        "X-Timestamp": timestamp,
        "X-Signature": signature,
    }

# 服务端验证
def verify_signature(method, path, body, headers, secret_key) -> bool:
    timestamp = headers.get("X-Timestamp", "")
    signature = headers.get("X-Signature", "")
    
    # 检查时间戳(防重放,5分钟窗口)
    if abs(time.time() - int(timestamp)) > 300:
        return False
    
    # 重新计算签名
    string_to_sign = f"{method}\n{path}\n{timestamp}\n{hashlib.sha256(body.encode()).hexdigest()}"
    expected = hmac.new(secret_key.encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()
    
    return hmac.compare_digest(signature, expected)

12.6 API Gateway 认证模式

集中认证 vs 分布式认证

集中认证(推荐):
┌──────────┐    ┌──────────────┐    ┌──────────┐
│  客户端   │───▶│  API Gateway  │───▶│  微服务   │
│          │    │  ① 验证 Token │    │ 信任 GW  │
│          │    │  ② 速率限制   │    │ 的转发   │
│          │    │  ③ 注入用户信息│    │          │
└──────────┘    └──────────────┘    └──────────┘

分布式认证:
┌──────────┐    ┌──────────────┐    ┌──────────┐
│  客户端   │───▶│  API Gateway  │───▶│  微服务   │
│          │    │  仅路由转发   │    │ 自己验证  │
│          │    │              │    │ Token    │
└──────────┘    └──────────────┘    └──────────┘

Token 内省 vs 本地验证

方式

Token 内省(Introspection)

本地验证(JWT)

原理

调用授权服务器验证 Token

本地用公钥验证签名

延迟

高(网络调用)

低(本地计算)

实时性

实时(可检查撤销)

延迟(依赖过期时间)

依赖

授权服务器必须可用

仅需公钥(JWKS)

适用

Opaque Token

JWT

12.7 Service-to-Service 认证

认证方式演进:
┌─────────────────────────────────────────────┐
│  Level 1: 无认证(内网信任)                  │
│  → 不安全,任何内部服务都可以调用             │
├─────────────────────────────────────────────┤
│  Level 2: Service Account + Token            │
│  → 静态凭证,需要手动管理和轮换              │
├─────────────────────────────────────────────┤
│  Level 3: Service Mesh mTLS                  │
│  → 自动证书管理,透明加密                    │
├─────────────────────────────────────────────┤
│  Level 4: SPIFFE/SPIRE                       │
│  → 统一工作负载身份,跨平台,自动轮换        │
│  → 这是我们在第19-21章要深入讨论的           │
└─────────────────────────────────────────────┘

12.8 API 认证方式对比

方式

安全性

复杂度

适用场景

API Key

⭐⭐

公开 API、低安全要求

Bearer Token (JWT)

⭐⭐⭐⭐

Web/Mobile API

mTLS

⭐⭐⭐⭐⭐

服务间通信

HMAC 签名

⭐⭐⭐⭐

高安全 API(支付)

SPIFFE SVID

⭐⭐⭐⭐⭐

云原生服务间通信

12.9 小结

  • Bearer Token(JWT) 是最通用的 API 认证方式

  • mTLS 提供最强的安全保障,适合服务间通信

  • API Gateway 集中认证 简化了微服务的认证逻辑

  • HMAC 签名 适合需要请求完整性验证的高安全场景

  • SPIFFE/SPIRE 是云原生时代服务间认证的最佳实践(详见第四部分)

  • 选择认证方式时需权衡:安全性、复杂度、性能、运维成本