KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
00 · IdP 与 SP(依赖方) — keel 龙骨
类型:主题概念 · 应用课对应:01 章 · 全景与选型
类型:主题概念 · 应用课对应:01 章 · 全景与选型
这一页只回答四件事:它为什么会出现、它是什么、它长什么样、它怎么工作。它不解释协议报文,也不讲选型。
一、它为什么会出现
一个团队里同时跑着四个内部系统:工单、报表、监控、代码托管。它们是不同的人在几年里分别搭起来的,每个系统都有自己的账号表。
于是每天都发生这几件事:
新人入职 → 开四个账号,漏掉一个,他第一天就有系统进不去
有人调岗 → 四个系统里改四遍权限,改到最后自己也记不清改到哪了
有人离职 → 只要漏关一个,他的密码还能登进去
它面对的需求是一句话:让"这个人是谁"这件事只被验证一次,所有系统都接受同一个结论。
不是"把四个系统合并成一个",也不是"给四个系统同步密码"——那两条路都要求每个系统继续自己保管密码。它要的是把验证这件事从每个系统里搬走。
二、它是什么
一句话:IdP 是那个"替所有应用验证身份"的系统;SP 是那些"不自己验密码、只接受 IdP 结论"的应用。
两个名字:
| 角色 | 全称 | 在这个故事里是谁 |
|---|---|---|
| IdP | Identity Provider,身份提供方 | 唯一一个存密码、问密码、判对错的地方 |
| SP | Service Provider,依赖方(OIDC 里也叫 RP) | 工单、报表、监控、代码托管——四个都属于它 |
它不是下面这三样东西,分清它们能省掉一大半困惑:
- 不是一个"统一的登录页"。 登录页只是 IdP 露在外面的一个界面;真正起作用的是它事后签出的那段结论。把 IdP 理解成"页面",就会在"为什么换个应用就自动进去了"上卡住。
- 不是"应用自己的一套账号"。 SP 侧通常一个密码字段都没有,它只记"我信哪个 IdP"。所以它那份用户列表常常是空的。
- 不是"应用之间的接口"。 IdP 与 SP 之间说话;SP 与 SP 之间从不说话。第二个应用能认出同一个人,靠的不是第一个应用告诉它,而是它俩问了同一个 IdP。
三、它长什么样
"谁是 IdP、谁是 SP"落成配置,是两处登记:SP 侧登记"我信谁",IdP 侧登记"我认得谁"。
SP 侧的登记:
issuer = http://localhost:8081/realms/sso-lab
client_id = sp-spa
redirect_uri = http://localhost:8090/callback
IdP 侧的登记:
client_id = sp-spa
redirect_uri = http://localhost:8090/callback
public client, no client_secret
两边对 redirect_uri 必须逐字符一致——它是安全边界,02 页 专门讲。
真跑起来时,IdP 的身份会以 iss 的名义出现在回跳地址里(环境:Keycloak 26.8.1,dev 模式,realm = sso-lab):
http://localhost:8090/callback
?state=AsoTwZFFJyDK-urhFMy_jw
&session_state=VnXksyjhgJexcsLOoOE5fc8c
&iss=http%3A%2F%2Flocalhost%3A8081%2Frealms%2Fsso-lab
&code=44f80113-b402-a38e-bbc0-56310447ebf8.VnXksyjhgJexcsLOoOE5fc8c.74717848-0bf1-4f44-81f2-e31422eb12c8
iss 里那个 http://localhost:8081/realms/sso-lab,就是 IdP 在发现文档里自报的 issuer:
issuer = http://localhost:8081/realms/sso-lab
authorization_endpoint = http://localhost:8081/realms/sso-lab/protocol/openid-connect/auth
token_endpoint = http://localhost:8081/realms/sso-lab/protocol/openid-connect/token
end_session_endpoint = http://localhost:8081/realms/sso-lab/protocol/openid-connect/logout
它必须和你实际访问它的地址逐字符一致。 如果你的应用从 http://127.0.0.1:8081 去访问,而文档里写的是 localhost,那么回跳里的 iss 与令牌里的 iss 都会是 localhost 那个值——和你在 SP 侧登记的 issuer 对不上,校验当场失败。这不是大小写写错了,而是 IdP 的"名字"就长在它的地址上。
四、它怎么工作
一次登录只有四步,其中一步是关键:
① 应用发现"这个访问者在我这儿没有会话" → 把浏览器交给 IdP
↓
② IdP 在自己的地址上问凭据 ← 只有这一步会看到密码,且发生在 IdP 的页面上
↓
③ IdP 把一段"这个人是谁"的结论交回应用
↓
④ 应用据此建自己的会话;此后每个请求只查自己的会话,不再回头问 IdP
第 ② 步是整件事的核心:密码从来没有经过应用。所以第 ④ 步之后,应用手里拿的是"有人替我确认过身份"这件事,而不是密码。
也正因为第 ② 步由 IdP 独占,第 ③ 步才能被第二个应用复用——两个应用问的是同一个 IdP。
五、它会带出哪些概念
- 断言与令牌:第 ③ 步交回来的那段"这个人是谁"就是断言,它需要一个载体,载体叫令牌。→ 01 页
- 重定向与回跳:第 ① 步不是应用自己走过去,是浏览器被点名走过去;结论交回来时也走同一条路。→ 02 页
- 会话与单点登出:第 ④ 步建的是"应用侧会话",而 IdP 侧还留着它自己的一份;两份都对得上才有单点登录,也才有登出的麻烦。→ 04 页
六、回到应用课
| 应用课里的那句话 | 现在你知道它为什么成立 |
|---|---|
| "认证:你是谁;授权:你能做什么 + 数据隔离" | IdP 只回答前一个问题;SP 拿到"是谁"之后能不能做某件事,仍然由 SP 自己判断 |
| "把'验身份'收敛到一个系统去做,其余系统只接受它的结论,就是单点登录" | 这句话里的"一个系统"就是 IdP、"其余系统"就是 SP——角色先立住,后面每个判断才有主语 |
| "对面用什么协议往往不是你能选的" | 两套协议换的是同一段结论的不同载体;"对面是谁"之所以一票决定,是因为要动的是 SP 侧接哪一段 |
这一页改变了你的哪个判断:你不再只问"登不上怎么修",而是先问**"这一步是 IdP 在说、还是 SP 在说"**——同一句"登录失败",出在 IdP 侧和出在 SP 侧,要去核对的东西完全不同。
→ 这一页的展开在应用课 01 章 · 全景与选型。
自测题
- 既然"SP 与 SP 之间从不说话",第二个应用凭什么认定"这个人就是刚才那个人"?
- IdP 的发现文档写着
issuer = http://localhost:8081/realms/sso-lab,而你从http://127.0.0.1:8081访问它——会在哪一步、以什么形式出问题?