提示:本网站现在为维护调试状态

JWT 認證安全最佳實踐 + OAuth2 vs SAML

Choyeon
Choyeon
2026年9月12日 1 分鐘閱讀 277 閱讀
590 字 2,317 字元 更新於 2026年11月8日
JWT 認證安全最佳實踐 + OAuth2 vs SAML
目錄

JWT 认证安全最佳实践 + OAuth2 vs SAML

JWT 因其无状态、跨服务易用被广泛采用,但配置不严谨会成攻击重灾区。现代系统常需第三方登录或企业 SSO,选对联邦协议也是架构师必修课。

JWT 安全实现要点

绝对不要使用对称密钥 HMAC 直接在前端签发(密钥会泄漏),生产用 RS256/ES256 非对称,公钥公开验证。严格白名单允许算法、用 timingSafeEqual 做 iss/aud 对比防时序攻击,jti 黑名单支持吊销。

import { createSign, createVerify, randomBytes, timingSafeEqual } from "node:crypto";

export interface JwtConfig {
    algorithm: "RS256";
    privateKeyPem: string;
    publicKeyPem: string;
    issuer: string;
    audience: string;
    accessTokenTtlSec: number;
    allowedAlgos: readonly string[];
}
export interface TokenPayload {
    sub: string; scopes: readonly string[]; jti: string;
    exp: number; nbf: number; iat: number; iss: string; aud: string;
}
const B64 = {
    enc: (b: Buffer) => b.toString("base64url"),
    dec: (s: string) => Buffer.from(s, "base64url"),
};
const DENIED = new Set<string>();

export function createJwt(cfg: JwtConfig, claims: Partial<TokenPayload> & { sub: string; scopes: readonly string[] }): string {
    const now = Math.floor(Date.now() / 1000);
    const header = { alg: cfg.algorithm, typ: "JWT", kid: "k1" };
    const payload: TokenPayload = {
        sub: claims.sub, scopes: claims.scopes,
        jti: randomBytes(16).toString("hex"),
        iat: now, nbf: now, exp: now + cfg.accessTokenTtlSec,
        iss: cfg.issuer, aud: cfg.audience,
    };
    const input = `${B64.enc(Buffer.from(JSON.stringify(header)))}.${B64.enc(Buffer.from(JSON.stringify(payload)))}`;
    const s = createSign("RSA-SHA256"); s.update(input);
    return `${input}.${B64.enc(s.sign(cfg.privateKeyPem))}`;
}

export function verifyJwt(cfg: JwtConfig, token: string): TokenPayload {
    const parts = token.split(".");
    if (parts.length !== 3) throw new Error("malformed");
    const [hB64, pB64, sB64] = parts;
    const header = JSON.parse(B64.dec(hB64).toString());
    if (!cfg.allowedAlgos.includes(header.alg) || header.alg === "none") throw new Error("alg not allowed");
    const ver = createVerify("RSA-SHA256"); ver.update(`${hB64}.${pB64}`);
    if (!ver.verify(cfg.publicKeyPem, B64.dec(sB64))) throw new Error("signature mismatch");
    const p = JSON.parse(B64.dec(pB64).toString()) as TokenPayload;
    if (!timingSafeEqual(Buffer.from(p.iss), Buffer.from(cfg.issuer))) throw new Error("iss");
    if (p.aud !== cfg.audience) throw new Error("aud");
    const now = Math.floor(Date.now() / 1000);
    if (p.exp < now) throw new Error("expired");
    if (p.nbf > now) throw new Error("not yet valid");
    if (DENIED.has(p.jti)) throw new Error("revoked");
    return p;
}

OAuth2 / OIDC / SAML 对比

OAuth2 是授权框架不是认证协议,OpenID Connect 在其之上加了 id_token 才是登录。SAML 2.0 是传统企业联邦协议,XML 格式兼容性强但移动端体验差。

特性 OAuth2 + PKCE OIDC (基于OAuth2) SAML 2.0
本质 授权(delegation) 认证(authentication) 认证+授权联邦
适用 移动端/SPA Web/移动/API 企业内部SSO
Token access_token access_token + id_token(JWT) SAML Assertion(XML)
安全性 需PKCE防code注入 原生支持nonce 签名XML流程复杂
移动端体验 好(App转场) 好 差(重定向多)
集成复杂度 中 低 高(双方元数据)

最佳实践

JWT 存敏感信息:短 TTL(5-15min) + refresh_token 轮换。SPA 用 HttpOnly Cookie 承载 refresh_token 避免 XSS。第三方登录场景统一用 OIDC。

X微博Telegram

本文作者

投票

你最希望 Rosetta 优先加入哪项功能?

社区投票(演示数据,可后台删除)

留言 (4)

0 / 3000
画画的小鱼
画画的小鱼fishgallery.art2026年9月21日

有个小问题:你文中用的是 @Async 注解,这个默认用的是 SimpleAsyncTaskExecutor,生产环境是不是最好手动配一个线程池?

考研加油鸭
考研加油鸭kaoyan-journey.xyz2026年9月21日

作为一个刚入行的后端新人,这篇文章帮我理清了好多概念,谢谢博主持续输出高质量内容!

代码幽灵
代码幽灵ghostdev.blog2026年9月20日

哈哈,楼主的踩坑经历和我一模一样!我当时就是没注意到这个配置,排查了整整两天,看到这篇文章泪目了。

游戏策划阿哲
游戏策划阿哲2026年9月20日

写得太好了,终于搞懂了分布式事务的几种方案区别,收藏了!

相關文章

GraphQL vs REST:從 7 個維度深度對比

GraphQL vs REST:從 7 個維度深度對比

終結選型焦慮:從網絡傳輸效率、前端開發體驗、後端演進成本、緩存策略、類型安全、安全風險、生態工具鏈 7 大維度系統對比 GraphQL 與 REST,給出清晰決策樹與混合架構模式。

1 分鐘閱讀
Prompt Engineering 入門:Few-Shot + CoT + 結構化輸出

Prompt Engineering 入門:Few-Shot + CoT + 結構化輸出

系統入門 Prompt Engineering 三大核心技術:Few-Shot 示例學習注入專業領域風格、Chain-of-Thought (CoT) 思維鏈引導複雜推理、JSON Schema 強制結構化輸出對接下游系統。附真實 prompt 模板和避坑指南。

1 分鐘閱讀
CQRS + Event Sourcing 架構模式解析

CQRS + Event Sourcing 架構模式解析

透徹解析兩種高複雜度分布式架構模式:CQRS 讀寫模型分離實現查詢極致性能、Event Sourcing 以事件作為唯一真相源實現全量審計與時間回溯,討論一致性/快照/冪等難點與反模式。

1 分鐘閱讀
測試金字塔:單元/整合/E2E 測試比例與落地

測試金字塔:單元/整合/E2E 測試比例與落地

系統解析測試金字塔架構:從底層單元測試(大量快速、Mock 隔離依賴)、中層整合測試(服務/數據庫/消息協作真實交互)、頂層 E2E 測試(真實用戶路徑少量精測)的推薦比例 70% / 20% / 10%,附項目覆蓋率指標與落地實踐。

1 分鐘閱讀
快速上手 FastAPI - 構建高性能 REST API

快速上手 FastAPI - 構建高性能 REST API

FastAPI 是現代 Python Web 框架中的佼佼者,基於類型提示自動生成文檔、支持異步操作、性能媲美 Node.js。本文將通過實戰項目帶你從零構建一個完整的 CRUD API,涵蓋路由定義、請求驗證、依賴注入、數據庫集成等核心特性,讓你在 30 分鐘內掌握 FastAPI 的精髓。

這篇文章需要存取密碼 4 分鐘閱讀
Alembic 深度指南:數據庫遷移 + 自動生成 + 分支合併

Alembic 深度指南:數據庫遷移 + 自動生成 + 分支合併

SQLAlchemy 官方遷移工具 Alembic 完全指南:從 env.py 配置、autogenerate 自動檢測模型變更(字段、索引、約束)、批處理腳本、downgrade 回滾策略,到多人併發開發時 migration 分支衝突、head 分叉合併的標準操作流程,附生產部署檢查表。

1 分鐘閱讀