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

推荐订阅源

aimingoo的专栏
aimingoo的专栏
S
Securelist
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
IT之家
IT之家
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
N
News and Events Feed by Topic
AI
AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Schneier on Security
Schneier on Security
Attack and Defense Labs
Attack and Defense Labs
Vercel News
Vercel News
腾讯CDC
Google DeepMind News
Google DeepMind News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
M
MIT News - Artificial intelligence
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
Netflix TechBlog - Medium
量子位
S
Schneier on Security
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
S
Security Affairs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
T
Tenable Blog
PCI Perspectives
PCI Perspectives
MyScale Blog
MyScale Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
W
WeLiveSecurity
N
News | PayPal Newsroom
P
Proofpoint News Feed
O
OpenAI News
C
CERT Recently Published Vulnerability Notes
B
Blog
Cisco Talos Blog
Cisco Talos Blog
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
MongoDB | Blog
MongoDB | Blog
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
Y
Y Combinator Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy

博客园 - 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