校门、食堂通行证和学生证:AuthN、AuthZ、OAuth 与 OIDC 是怎么工作的

这件事你大概做过上千次了。你走到校门口,掏出你的 NFC 学生证,在读卡器上「滴」一下,绿灯亮,门锁”咔嗒”一声弹开,你走进校园。

感觉是一瞬间的事。但就在这一秒钟里,学校其实回答了两个问题:

  1. 这是一张真的卡吗?(学校真的发过这张卡吗?)
  2. 这张卡是你的吗?(学校是不是把这张特定的卡发给了你这一个特定的学生?)

两个答案都是”是”,门才开。任何一个是”否”,门都不会开——而且很可能会有老师走过来问你怎么回事。

就这样。这就是**身份验证(authentication)**背后全部的想法——学校在确认你就是你。

这篇文章剩下的大部分内容,也都跟”确认”有关。但问题在变,答案在变,所用的比喻也跟着变。读完之后,你会知道 AuthNAuthZMFAOAuthOIDC 到底是什么意思——哪怕这些词听起来像是机器人打了个喷嚏。

我们从校门开始。

身份验证(AuthN):你是谁?

当你在校门口的读卡器上「滴」一下你的 NFC 卡时,学校只做了一件事:确认你的身份。这件事的技术名词叫身份验证(authentication),通常缩写成 AuthN

系统会问两个问题:

  • 这张卡是真的吗?(卡里有一个序列号,已经登记在学校的数据库里。)
  • 这张卡是你的吗?(你的照片、姓名、学号都存在学校的服务器上。)

两个答案都是”是”,门才”咔嗒”一声打开。任何一个是”否”,门就不动。

AuthN 只回答一个问题:你是谁?

整个过程只用一秒钟。但知道”你是谁”,并不等于学校知道你”可以做什么”。那是下一个问题。

授权(AuthZ):你被允许做什么?

进了校门之后,你的 NFC 卡还在工作——但是另一种工作。你走过的每一扇门都有读卡器,每一个读卡器都会问同一个问题:“这个学生被允许进这扇门吗?”

这件事的技术名词叫授权(authorization),通常缩写成 AuthZ

在校园里是这样运作的:

  • 图书馆门——任何学生都能开。你一刷,它一响,你就进去。
  • 教师休息室——对学生是锁着的。只有教职工的卡能开。
  • 体育馆——任何学生都能进,但访客不行。

知道你是谁(这是校门口那次 AuthN 给出的答案)——但卡也知道你是哪种学生。七年级的学生可以开图书馆的门。老师可以开教师休息室的门。访客哪扇都开不了。

💡AuthN 与 AuthZ 的区别

AuthN 在校门口发生一次。AuthZ 在每一扇门前都发生。 你只需要证明一次”你是谁”,但你每次刷卡,系统都要再检查一次”你能做什么”。

最让人困惑的是这一条:你通过了身份验证,并不等于你被授权了。

你是一名真的学生,你的卡也是真的,校门放你进来了(AuthN ✔)。你走到教师休息室门前刷了一下,门还是锁着(AuthZ ✘)。系统知道你是 Neo,只是觉得你不应该进去。

这就是 AuthN 和 AuthZ 一起工作的样子。它们问的不是同一个问题——甚至连接近都谈不上。

多因素认证(MFA):你真的是你吗?

图书馆的门不太在意是谁在刷卡——几乎任何学生都能开。但校园里有些门不一样。服务器机房——那里面存着每一个学生的成绩和档案——那扇门不会只信一次 NFC 刷卡。

要开这扇高安全等级的门,你需要两样东西,而不是一样:

  • 你拥有的东西——你的 NFC 卡(跟校门口用的同一张)。
  • 你知道的东西——学校在开学时发给你的一个六位 PIN 码。

你刷一下卡,读卡器要你输入 PIN 码,你把它敲进去,门开了。

这件事的技术名词叫多因素认证(multi-factor authentication),通常缩写成 MFA。“多”的意思是不止一个因素;“因素”的意思是三类证据中的其中一类

一共有三类证据,叫因素类别(factor class)

因素类别它是什么校园里的例子
你拥有的东西一个实物你的 NFC 卡
你知道的东西你脑子里一个秘密你的六位 PIN 码
你本身的东西你身体的一部分你的指纹(高安全等级的门那里扫描)

单因素检查只用其中一种。校门口只用一种——你的 NFC 卡(你拥有的东西)。高安全等级的门用两种——你的卡(拥有)+ 你的 PIN(知道)。

💡MFA 的规则

攻击者必须破解两个不同类别的因素——而不是同一类的两个。偷两张卡没用(攻击者还是需要 PIN)。卡 + PIN 才行。

在校门口,一个因素(卡)就够了——学校只想知道你是真的学生。在高安全等级的门那里,要两个因素——因为门里面的东西(你的成绩、你的档案)更有价值。

OAuth 2.0:安全地把权限借出去

到目前为止,所有事情都发生在校园内部。但是,如果校园外面的一个系统需要代替你做事呢?

比如说,学校有一款食堂 App。你把它装到手机上,想用它来买午饭。这个 App 需要知道你是谁,才能从你的校园账户上扣钱——但你又不想把校园密码告诉这个 App。(那个密码你在所有地方都用;如果食堂 App 被黑了,攻击者就能登进你的成绩系统、考勤系统、邮箱。)

这正好是 OAuth 2.0 解决的问题。

OAuth 2.0 是一份协议——一组规则——用来做委托授权(delegated authorization)。学校不会把校园密码交给食堂 App。相反,学校给食堂 App 一张临时通行证。我们把这张通行证叫做访问令牌(access token)

过程是这样的:

  1. 你在食堂 App 上刷一下你的卡(或者点”用校园账号登录”)。
  2. 学校问:“你愿意把这张通行证发给食堂 App,让它能买饭吗?”
  3. 你说”好”。
  4. 学校发出一张临时通行证——访问令牌——给食堂 App。
  5. 通行证上写着:“这个学生可以买饭。”
  6. 通行证一个小时后失效。

食堂 App 每次帮你买饭都用这张通行证。它永远看不到你的校园密码。如果 App 被黑了,攻击者拿到的也只是这张临时通行证——而且通行证很快就会过期。

这出戏里有三个角色:

  • 你,这个学生——技术名词叫资源拥有者(resource owner)(你拥有你的数据和你的权限)。
  • 学校——技术名词叫授权服务器(authorization server)(发通行证的那个系统)。
  • 食堂 App——技术名词叫客户端(client)(拿到通行证并使用它的那个系统)。

⚠️OAuth 不是身份验证协议

OAuth 是用来做授权(AuthZ)的,不是身份验证(AuthN)。 当一个教程说”用 Google 登录”时,它其实说的是 OpenID Connect——也就是 OAuth 加上一个身份层。单纯的 OAuth 不会让你”登录”——它只是给另一个系统发一张通行证。

三个角色的连接关系是这样:

flowchart TB S["Student<br/>(resource owner)"] SCH["School<br/>(authorization server)"] C["Cafeteria App<br/>(client)"] AT["Access Token<br/>temporary digital pass<br/>(OAuth)"] ID["ID Token<br/>verified student ID,<br/>photo, name<br/>(OIDC only)"] S -- "taps NFC card at gate" --> SCH SCH -- "issues" --> AT SCH -- "issues (OIDC)" --> ID AT --> C ID --> C C -- "uses pass to buy lunch" --> S style S fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style SCH fill:#e3f2fd,stroke:#1976d2,stroke-width:3px style C fill:#fff9c4,stroke:#f57c00,stroke-width:2px

这张图从上往下读。学生在最上面,在校门口的读卡器上刷一下卡。学校给食堂 App 发两张令牌:访问令牌(OAuth)和——在使用 OIDC 时——一个 ID 令牌(下一节)。食堂 App 用这两张令牌代替学生买饭。学生从来不会交出密码。

OpenID Connect(OIDC):在通行证上加上”你是谁”

OAuth 给食堂 App 一张临时通行证——但通行证上只写着*“这个学生可以买饭”。它没说是哪一个学生*。这是个问题:食堂需要知道该谁的校园账户上扣钱。

OpenID Connect(OIDC) 解决了这个问题。OIDC 是 OAuth 加上身份。学校在发出临时通行证的同时,还会再发第二张令牌——ID 令牌(ID token)——里面装着这个学生被核验过的身份信息:

  • 学号
  • 照片
  • 全名
  • 班级 / 年级

ID 令牌由学校签名(这样食堂 App 才能验证它是真货),它会告诉食堂 App 到底在买饭。

所以现在有两张独立的令牌

  • 访问令牌——临时通行证(OAuth)。说你能做什么。
  • ID 令牌——被核验过的身份(OIDC)。说你是谁。

两张令牌通常都是 JWT(JSON Web Token)的格式,也就是”带签名的 JSON 对象”。但它们承担不同的职责。如果你想深入了解,可以去看 OpenID Connect Core 1.0 规范——里面有令牌格式、支持的所有流程、以及加密签名的具体规则。

JWT 的 scope:贴在通行证上的标签

到这里,你已经好几次听到”令牌(token)“这个词了。令牌就是学校发出来的一小段数据——一张临时通行证,上面写着你是(或者你能做什么,或者两者都写)。

如今最常见的令牌格式叫 JWT——JSON Web Token。JWT 是一个字符串,看起来像是三段很长的随机词用点连起来:eyJhbGc...header.eyJzdWI...payload.SflKxw...signature。第一段是 header(用了什么算法),第二段是 payload(真正的数据——你的名字、你的权限,等等),第三段是 signature(一个加密印章,证明这个 JWT 没人改过)。

JWT 能装很多东西,但其中最重要的是一列scope(授权范围)scope 是通行证上的一个标签,写着这张通行证能做什么

回到食堂的例子:

  • "library access"——可以借书。
  • "cafeteria purchases"——可以买饭。
  • "gym entry"——可以用体育馆。
  • "grades:read"——可以读成绩(这就有点危险了)。

食堂 App 的令牌上只有 "cafeteria purchases"。它没有 "grades:read"。所以当它想读成绩的时候,学校的系统会说:“这张通行证没贴那个标签——拒绝。”

但如果令牌到达时根本没有任何 scope 呢?它还是一张真通行证——签名能验过——但它上面没有标签。接收方的系统不知道这张通行证是拿来开哪扇门的。

这种情况有两种策略:

  • 默认拒绝(default-deny,稳妥)——因为通行证没有标签,系统直接拒绝。“这张通行证没有 scope,那我们一律拒绝。”
  • 默认放行(default-allow,冒险)——系统看不出它不能做什么,干脆让它什么都能做。

⚠️没有 scope 的 JWT 是危险的

一个表现良好的 API 会把一个没有 scope 字段的 JWT 当成”未授予任何 scope”——在功能上等同于拒绝。最经典的错误就是默认放行:食堂 App 突然能看成绩、看考勤、看任何东西,因为系统分不清它不能做什么。

flowchart TB J["Cafeteria App receives JWT"] Q{"Does JWT have a<br/>scope field?"} D["Default-deny (safer)<br/>refuse the purchase"] A["Default-allow (risky mistake)<br/>allow everything<br/>cafeteria can see grades!"] R["Read scopes"] M{"Are requested scopes<br/>in granted set?"} Y["Allow"] N["Deny"] J --> Q Q -- "NO" --> D Q -- "NO" --> A Q -- "YES" --> R R --> M M -- "YES" --> Y M -- "NO" --> N style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style A fill:#ffebee,stroke:#c62828,stroke-width:2px style Y fill:#e8f5e9,stroke:#388e3c,stroke-width:2px style N fill:#ffebee,stroke:#c62828,stroke-width:2px

这张图画出了决策树。如果 JWT 没有 scope 字段,稳妥的选择是拒绝(左上分支)。如果有 scope 字段,系统就读出 scope,然后检查”请求的动作”是不是落在”授予的集合”里。

五个概念,各用一段话讲完

读到这里,你已经能回答”AuthN 和 AuthZ 有什么区别”了。你也能跟朋友讲清楚,为什么 OAuth 不等于”登录”。

一句话回顾:

  • AuthN = 在校门口的读卡器上滴一下你的 NFC 卡。
  • AuthZ = 滴一下之后,哪些门会打开。
  • MFA = 在高安全等级的门那里要卡 + PIN。
  • OAuth = 给另一个系统(比如食堂 App)一张临时通行证,让它代替你做事。
  • OIDC = 一张临时通行证,再附上一张核验过的学生证。
  • JWT 里没有 scope = 一张没贴标签的通行证——老师看不懂,系统也可能出安全问题。

如果你想从这里接着往前走,文章之外还有更多内容。想做实操的下一步——“我自己要怎么保管密码?“——可以去看 密码管理器(Password Managers) 那篇。如果你喜欢这种风格,又想看更偏管理层的深度版——聊聊当身份认证在组织层面缠成一团*时会怎样——可以去看 质量天花板(The Quality Ceiling)——同一个比喻的味道,不同的尺度。

References

  1. RFC 6749 — The OAuth 2.0 Authorization Framework (IETF). https://datatracker.ietf.org/doc/html/rfc6749
  2. OpenID Connect Core 1.0 specification. https://openid.net/specs/openid-connect-core-1_0.html
  3. RFC 7519 — JSON Web Token (JWT) (IETF). https://datatracker.ietf.org/doc/html/rfc7519
  4. NIST SP 800-63B — Digital Identity Guidelines: Authentication and Lifecycle Management. https://pages.nist.gov/800-63-3/sp800-63b.html

评论

请接受“功能性”Cookie 类别以查看和发表评论。