惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
I
InfoQ
The Register - Security
The Register - Security
L
LangChain Blog
H
Help Net Security
The GitHub Blog
The GitHub Blog
S
Schneier on Security
博客园 - 【当耐特】
W
WeLiveSecurity
Attack and Defense Labs
Attack and Defense Labs
IT之家
IT之家
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Google DeepMind News
Google DeepMind News
The Cloudflare Blog
H
Heimdal Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Y
Y Combinator Blog
雷峰网
雷峰网
N
Netflix TechBlog - Medium
Security Archives - TechRepublic
Security Archives - TechRepublic
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
L
Lohrmann on Cybersecurity
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Exploit Database - CXSecurity.com
P
Privacy & Cybersecurity Law Blog
G
GRAHAM CLULEY
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
V
Visual Studio Blog
博客园 - 聂微东
PCI Perspectives
PCI Perspectives
Last Week in AI
Last Week in AI
A
Arctic Wolf
宝玉的分享
宝玉的分享
T
The Blog of Author Tim Ferriss
S
Secure Thoughts
T
Threat Research - Cisco Blogs
GbyAI
GbyAI
云风的 BLOG
云风的 BLOG
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
SegmentFault 最新的问题
SecWiki News
SecWiki News
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
Schneier on Security
Schneier on Security
P
Proofpoint News Feed
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
AI
AI
Engineering at Meta
Engineering at Meta

博客园 - Earic

背着房贷的程序员,不该继续用“AI替代焦虑”浪费时间 从 Prompt 到 Loop:拆解 AI 工程化四范式的演进逻辑与落地边界 Claude Code 封号与"隐藏标记"争议:一份基于公开资料的核验清单 Go 跨平台真香:我把整个服务端塞进了客户端,用户开箱即用 Agent 直接操作数据库?别急,先看懂这三条路线 用本体论重塑现实:破解大语言模型幻觉的疯狂设想 前端仔接手C#屎山重构:数据库迁移这趟浑水到底有多深? OpenAI Codex 频繁写 SSD 写入问题的真相与应对方案 向量数据库不是银弹:从枚举漏检到 ReACT 多轮召回的实践路径 AI浪潮下的“幸存者”:从焦虑的碎碎念到构建普通人的新核心竞争力 差点被这套AI工具搞离职...搞懂MCP和Skill后,我发现宇宙的尽头是“写小作文” 花 Opus 的钱买到 Sonnet?一行 Python 代码揭穿 API 服务商的“降本增效”骗局 当 rm -rf 发生在物理机节点:从 Virtualizor 漏洞看你的容灾架构为何不堪一击? 深夜惊魂:一行代码让内存爆炸!从 5秒超时到 50ms 响应,我是如何重构 AI 网关的 只有5%的运营人看懂了:从“死积分”到“数字资产”,36期AI分红背后的博弈论 每秒万级Tick的生死时速:技术总监在Golang与Rust间的深夜抉择 这才是多数据源的正确打开方式!MyBatis-Plus vs Hibernate 底层原理大揭秘,别再瞎配了 拒绝背锅!服务器卡顿CPU却空闲?一文揪出磁盘I/O这个“隐形杀手” 凌晨3点服务器被CPU打爆!从裸奔到铜墙铁壁,这套纵深防御方案救了我的命 【深度解析】SkyWalking 10.2.0版本安全优化与性能提升实战指南 intellij 自动导包 用户中心 - 博客园 用户中心 - 博客园 用户中心 - 博客园 bcrypt 加密 用户中心 - 博客园 用户中心 - 博客园 用户中心 - 博客园 用户中心 - 博客园 用户中心 - 博客园
从 Ticket-v1 到 OIDC:一场跨越十年的身份认证架构演进与平滑迁移实战
Earic · 2026-07-26 · via 博客园 - Earic

从 Ticket-v1 到 OIDC:一场跨越十年的身份认证架构演进与平滑迁移实战-900x383

场景开场

如果你接手过一个用了七八年的老系统,大概率见过这样的场面:认证中心是十年前搭的 CAS,业务侧从单体 Web 长成了几十个微服务,又冒出小程序、App、API 网关。运维半夜被告警吵醒,一看是认证中心 /serviceValidate 被打爆了,因为每个微服务、每次跳转都要回中心校验一次 Ticket。想升级到 OIDC,又不敢动,因为老应用一堆 CAS Client SDK,牵一发动全身。

这篇文章不讲协议扫盲,只解决一件事:Ticket-v1 和 OIDC 到底差在哪,为什么现在必须迁,以及怎么在不停业务的前提下平滑切过去。后面有一份四步迁移清单和两个真实踩坑点,建议先收藏,真到要动手改造的时候,能直接拿去对着做。

一句话结论

先把结论摆前面,省得你读到一半划走:

Ticket-v1 是有状态的反向校验,OIDC 是无状态的本地验签。前者把校验压力全压在认证中心,后者把校验能力下放到每个应用。这一个差别,决定了 Ticket-v1 天然扛不住微服务和高并发,而 OIDC 天生就是给分布式架构准备的。

所以问题从来不是"OIDC 好不好"而是"你还要不要继续把认证中心当单点瓶颈养着"选型的时候记住一句话:新项目直接 OIDC,老系统别硬切,用协议叠加 + 分批迁移。

两个时代

Ticket-v1 出生在浏览器还只会做重定向的年代。那时候的 SSO,逻辑很朴素:用户在认证中心登录成功,中心发一张短效随机字符串(比如 ST-12345-x)给浏览器,浏览器带着这张票跳回业务系统,业务系统再悄悄回中心问一句"这张票是不是真的、是谁的"票用完就作废,跟你去电影院检票一个流程。

OIDC 是完全另一个思路。它建立在 OAuth 2.0 之上,颁发的是一个 ID Token,本质是一个用私钥签过名的 JWT。里面直接写好了用户是谁、什么时候过期、有哪些属性。应用拿到之后不需要再问中心,用中心公开的公钥(JWKS)在本地验签就行。

一个像纸质门票,检票员必须一张张核;一个像带防伪芯片的电子票,闸机自己就能刷。两者不是简单的新旧,而是从"中心化查验"到"去中心化信任"的架构转向。

01-对比表:分左右两列。左列标题'Ticket-v1(票据校验)

校验机制

这是两者最要命的差别,也是很多老系统扛不住并发的根源。

Ticket-v1 的校验路径

  1. 用户登录成功,认证中心把 Ticket 塞给浏览器。
  2. 浏览器带着 Ticket 跳回业务系统。
  3. 业务系统必须再发一次 HTTP 请求到认证中心的 /serviceValidate 接口,问这张票有效吗、是谁。
  4. 中心校验成功后返回用户 ID,同时把这张 Ticket 立刻销毁。

看上去还行?把它放到 50 个微服务、每次跨服务调用都需要身份传递的场景下,认证中心瞬间变成整个系统的心脏起搏器:它一停,全公司登录全挂。

OIDC 的校验路径

  1. 用户登录成功,中心颁发一个签名过的 ID Token(JWT)。
  2. 应用拿到 Token,用中心公开的 JWKS 公钥在本地直接验签
  3. 只要签名对、没过期、issuer 和 audience 匹配,就直接信任里面的用户信息。

中心只需要在启动时被拉一次公钥,之后应用端可以脱网校验成千上万次请求。这就是为什么 API 网关(Kong、APISIX、Envoy)都原生支持 OIDC,但基本没人给 Ticket-v1 做插件——它压根不适合网关场景。

02-时间线:上下两条流程对比。上半部分标题'Ticket-v1

生态差距

光有协议差异还不够,真正让 OIDC 碾压式领先的是它的标准化生态

Ticket-v1 时代,每家厂商的返回格式都不一样:有的返回 XML,有的返回一段拼字符串的伪 JSON,有的连 HTTP 状态码都乱用。接入一个新系统,第一件事是问对方要接口文档,接下来两天都在处理格式差异。

OIDC 把这些都规范化了,几个标准端点你记住就行:

  • /.well-known/openid-configuration:自动发现,一个 URL 拿到所有端点配置。
  • /authorize:登录入口。
  • /token:换取 Token。
  • /jwks:公钥集合,验签用。
  • /userinfo:补充用户信息。

结果就是 Spring Security、Keycloak、Auth0、Authing、APISIX、Kong 全都开箱即用。你在配置文件里填一个 issuer URL,其余的端点、公钥、算法它自己去发现。老 CAS 那套自定义协议,光让新同事看懂就得花半天。

错误姿势

讲迁移方案前,先说个反面案例。见过不止一个团队,一拍脑袋决定"这个季度全部切到 OIDC"然后三个月后灰头土脸滚回来:

  • 老应用几十个,CAS Client SDK 各种版本混用,改动全部代码得连测两个月。
  • 一次性切换那天,某个边缘系统忘了升级,用户登录后一直白屏。
  • 用户属性对不齐,新应用拿到 JWT 里没有 dept_id,业务逻辑直接崩。
  • 单点注销跟老 CAS SLO 不兼容,用户以为退出了,结果另一个页面还是登录态。

如果你们线上也在计划这种"大爆炸式切换"建议对照后面这套方案再评估一下。很多迁移事故不是技术不行,是节奏没控好。认证系统这种东西,一旦影响所有员工登录,回滚成本比想象中高得多

四步迁移

正确的姿势是"IdP 叠加 OIDC 协议 + 应用端分批渐进"四步走,每一步都可以独立验证、独立回滚:

第一步:认证中心叠加 OIDC 协议层

不动老的 CAS 校验接口,在中心侧扩出 OIDC 能力:

  • 用 Apereo CAS 的话,直接开 cas-server-support-oidc 模块。
  • 自研中心,就加一层 OIDC Adapter,把 /authorize/token 请求转换到内部登录逻辑。
  • 老中心动不了,就前面挂一个 Keycloak,把上游身份源指向老 CAS。

第二步:打通全局会话

这一步是无感 SSO 的关键。让 OIDC 流程和 CAS 流程共用同一个全局会话 Cookie(比如 CASTGC)。用户访问 OIDC 新应用,中心检查到全局会话,直接免密颁发 ID Token;访问老应用同理,直接免密发 Ticket。

第三步:应用端分批切换

  • 新应用、微服务、App、网关一律直接上 OIDC。
  • 老应用逐个替换 CAS Client SDK 为标准 OIDC Client。
  • 完全动不了的祖传系统,在 API 网关层做 OIDC 认证,把用户信息通过 X-User-Id 这类 Header 透传给后端。

第四步:审计并下线 Ticket 接口

/serviceValidate 的访问日志,确认连续几周没有任何调用了,再正式下线老模块。不要凭感觉,一定要凭日志。

看到这里,如果你们团队正好在做类似改造,建议把这四步单独拎出来对齐一下。很多迁移拖成一年半,不是技术问题,是没人把节奏切成可交付的小步。

03-流程图:4 个方框从上到下用箭头连接,代表迁移四步。第 1

网关兜底

单独拎出来讲第三步里最实用的一招:用 API 网关兜底老系统

很多公司有那种"改不动、也没人敢改"的老服务,代码是外包写的,人早跑了。这类系统直接上 OIDC 客户端改造不现实,但你可以把它挡在网关后面:

  • 网关(APISIX / Kong / Envoy Gateway)配置 OIDC 插件,负责跟认证中心走标准协议。
  • 网关拿到 ID Token,本地验签,解出用户信息。
  • 通过自定义 Header(例如 X-User-IdX-User-Roles)注入到后端请求里。
  • 老服务继续用它熟悉的方式从 Header 读用户 ID,一行代码不用改。

注意一个细节:网关到后端这段链路必须是内网可信的,不然攻击者伪造 Header 就直接绕过认证了。生产环境里,要么走内网 VPC,要么在网关和后端之间加一层 mTLS。这个坑我见过团队栽过,不点名。

这段建议转给做网关和运维的同事,网关侧其实能替业务侧扛掉一大半迁移工作量,前提是配置得对。

04-层级图:从上到下三层。第一层'用户浏览器';第二层'API

坑一:SLO

迁移里最容易被忽视的一个大坑:单点注销机制不一致

老 CAS 的 SLO 是这么干的:用户在中心退出后,中心主动往每个业务应用发一个 HTTP POST,通知它们清 Session。这套机制的前提是——中心得知道每个应用的回调地址,而且这些地址得在网络上可达。

OIDC 的做法完全不同,它有几种:

  • Front-Channel Logout:通过 iframe 加载各应用的登出 URL,让浏览器帮忙广播。
  • Back-Channel Logout:中心直接向应用后端发 logout token。
  • 短 Token + Refresh Token:干脆不做同步注销,让 Token 自然过期。

迁移过渡期新旧混跑,最容易出现"用户以为退出了,其实另一个页面还是登录态"的诡异现象。给你一个务实建议:

过渡期先把 ID Token 有效期调短,比如 5 到 15 分钟,配合 Refresh Token 做续期。

这样即使同步注销失效,最多十几分钟后 Token 也就自动作废了。等所有应用都切到 OIDC,再统一上 Back-Channel Logout,能少掉一大堆诡异 bug。

坑二:Claims

第二个大坑:用户属性映射对齐

老 Ticket-v1 时代,很多系统的习惯是从中心只拿一个 username,剩下的信息(部门、角色、工号)自己再调用用户中心接口反查。这种模式下,用户中心的 QPS 一直很高,因为每个业务都在反复问同一个人是谁。

切到 OIDC 是个绝佳的重构机会。你可以在 IdP 侧一次性把常用属性塞进 ID Token 或者 /userinfo 端点里,让业务直接从 JWT 解出来就够用。

建议按 OIDC Standard Claims 规范来对齐,别自己乱起名字:

  • sub:稳定的用户唯一 ID(这个是必须的,且永远不要用 email 或 username 当唯一 ID,因为它们可能变)。
  • email / email_verified:邮箱和验证状态。
  • preferred_username:展示用的用户名。
  • 自定义 claims 加前缀,比如 https://yourcompany.com/dept_idhttps://yourcompany.com/roles,避免和标准字段冲突。

注意 Token 别塞太胖。见过团队一股脑把所有权限点塞进 JWT,结果 Token 大到 8KB,每次 HTTP 请求 Header 都爆了。原则是:身份属性放 Token,动态权限走 API 查

上线清单

把这篇里能直接用的东西压缩成一份检查清单,收藏起来,动手改造前对着过一遍:

选型判断

  • 新项目、微服务、App、SPA、API 网关:直接选 OIDC,不用犹豫。
  • 需要对接高校统一认证、老国产 CAS、政企内网旧系统:可能得同时兼容 Ticket-v1。
  • 单体、内网、低并发、10 年不动的老系统:现有 CAS 能跑就先别动。

迁移前

  • 认证中心是否支持叠加 OIDC,不支持就前挂 Keycloak。
  • 全局会话 Cookie 是否在新旧协议间共享。
  • Claims 命名规范是否提前拉齐(尤其是 sub)。
  • Token 有效期先调短,5 到 15 分钟。

迁移中

  • 新应用一律 OIDC,别再新增 CAS Client。
  • 无法改造的老系统走网关兜底,网关到后端要有内网隔离或 mTLS。
  • /serviceValidate 加访问日志,标注调用方。

迁移后

  • 连续两周零调用后,再下线老 Ticket 接口。
  • 补上 Back-Channel Logout。
  • JWKS 公钥轮换机制要提前演练一次,别等到出事才知道客户端不会缓存。

写在最后

认证协议的演进,本质上是架构信任模型的演进:从"什么都要问中心"到"中心只负责签发,剩下的自己验"这一步跨过去,不只是换个协议,是让整个系统的身份层从瓶颈变成基础设施。

如果这篇对你有用,欢迎点个赞。团队里正好有人在推 SSO 升级,也可以顺手转给他,能少绕不少弯路。如果你们踩过比这更复杂的迁移场景,比如多 IdP 联邦、跨集团账号打通,评论区聊聊,我挑几个典型的下次专门写一篇。

我是爱三味,做后端架构做到现在,越发觉得——好的技术方案,从来不是最新的那个,而是能让你在半夜三点睡得着的那个
gzh-tg-1