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

推荐订阅源

A
About on SuperTechFans
D
DataBreaches.Net
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
S
Secure Thoughts
Y
Y Combinator Blog
The Last Watchdog
The Last Watchdog
L
LINUX DO - 最新话题
V2EX - 技术
V2EX - 技术
腾讯CDC
GbyAI
GbyAI
G
Google Developers Blog
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Microsoft Security Blog
Microsoft Security Blog
Jina AI
Jina AI
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
MyScale Blog
MyScale Blog
Help Net Security
Help Net Security
K
Kaspersky official blog
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
AI
AI
MongoDB | Blog
MongoDB | Blog
Scott Helme
Scott Helme
J
Java Code Geeks
Engineering at Meta
Engineering at Meta
H
Heimdal Security Blog
H
Help Net Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
S
Security Affairs
TaoSecurity Blog
TaoSecurity Blog
The GitHub Blog
The GitHub Blog
Hacker News: Ask HN
Hacker News: Ask HN
Martin Fowler
Martin Fowler
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Project Zero
Project Zero
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI

博客园 - 叫我安不理

C#如何优雅处理引用类型的深拷贝 老马失前蹄,竟然在数据库外键上翻车了,重温外键级联 字符编码知多少(二) 字符编码知多少(一) 给自己看的mongoDB快速入门 优雅求模,一致性哈希算法 浅谈为什么我讨厌分布式事务 为什么说方法的参数最好不要超过4个? C#代码如何影响CPU缓存速度? 浅谈.NET微服务架构的演变 C#网络编程(六)----Socket编程模型 C#网络编程(五)----细嗦TCP粘包 C#网络编程(四)----HttpClient C#网络编程(三)----HTTP协议 C#网络编程(二)----网络层/链路层 C#网络编程(一)----应用层/传输层 重生之我是操作系统(十)----I/O管理 重生之我是操作系统(九)----文件管理(下) 重生之我是操作系统(八)----文件管理(上) 重生之我是操作系统(七)----内存管理(下)
为什么OAuth2与SSO经常混为一谈?
叫我安不理 · 2025-11-08 · via 博客园 - 叫我安不理

简介

最近在工作中遇到了一个问题,在实现OAuth2的过程中,发现公司的实际落地与理论不完全相同。故此复习一下。

What is OAuth2?

OAuth2(OAuth2.0)是一个开放标准的授权框架,用于第三方应用(客户端)在取得用户(资源所有者)的授权下,可以访问用户敏感信息。而无需向第三方应用暴露账号密码

核心是"授权"而非"认证"

  1. 设计之初聚焦于权限管理
    OAuth2诞生的初衷是为了避免第三方应用获取用户的原始密码,同时让用户(资源所有者)自主控制第三方应用(客户端)对自己敏感信息的访问权限(比如只读,修改,删除),其本质是"授权第三方有限度的使用资源"

  2. 本身不参与认证
    在OAuth2流程中,用户身份的验证始终由资源所有者的平台负责(比如微信,GITHUB),由它们提供Login页面。
    OAuth本身不参与用户身份的验证,它只是在验证通过后,传递"已授权"的凭证

  3. 仅仅是一份授权证明
    OAuth2最终发放的是"访问令牌(Access Token)",它仅仅代表用户允许第三方应用如何访问特定资源,不包含用户身份信息,也不能作为用户身份的证明。

举个例子,使用该Access Token在https://www.jwt.io/ 中解析。eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMzQ1Niwic2NvcGUiOiJwcm9maWxlIG9wZW5pZCIsImV4cCI6MTczMzcwMjQwMCwiaWF0IjoxNzMzNjk4ODAwLCJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
image

核心角色

OAuth2定义了4个核心角色,所有流程都围绕这4个角色展开

角色 含义 举个例子
资源所有者 用户本身,有权决定是否授权客户端访问自己的资源 使用微信的你
客户端 第三方应用,希望访问用户(也就是你)的敏感信息 比如小红书希望访问你微信上的照片,头像,昵称等image
授权服务器 由资源服务器提供,验证用户的身份,生成授权凭证(Access Token) 微信的授权服务器 image
资源服务器 存储受保护资源的服务器,接收并验证客户端的Access Token 微信的用户信息服务器(存储你的头像、昵称等,只有验证令牌后才返回)。image

核心授权类型(Grant Type)

OAuth2根据客户端的类型(是否有服务器,是否能安全存储密钥)定了多种Grant Type。

  1. 授权码模式(Authorization Code)

    • 适用场景: 有自己服务器的客户端,能够安全存储客户端密钥,不会暴露给前端
    • 特点: 通过授权码间接获取访问令牌,是最常用也是最安全的模式。
  2. 隐式模式(Implicit)

    • 适用场景: 有自己服务器的客户端(比如无需与后端交互的纯前端应用),无法安全存储客户端密钥(密钥会暴露在前端代码中)
    • 特点:跳过“授权码”步骤,直接从授权服务器获取访问令牌(通过URL片段返回),不返回刷新令牌。
    • 缺点:访问令牌直接暴露在前端,安全性较低(可能被拦截)。
  3. 密码模式(Resource Owner Password Credentials)

    • 适用场景:客户端与资源所有者高度信任(如公司内部应用),用户愿意向客户端提供账号密码。
    • 流程:用户直接向客户端输入账号密码,客户端拿着密码向授权服务器请求访问令牌(如“公司内部APP用域账号密码登录,获取员工信息系统的访问权限”)。
    • 缺点:客户端获取了用户密码,违背OAuth“不暴露密码”的初衷。
  4. 客户端模式(Client Credentials)

    • 适用场景:客户端访问自己的资源(非用户个人资源),无需用户授权。
    • 流程:客户端直接用自己的客户端ID和密钥向授权服务器请求访问令牌(如“天气APP的后端服务,用自己的凭证获取天气数据API的访问权限”)。

重点关注授权码模式(Authorization Code)即可,剩下的三种纯属凑数。谁敢在生产环境暴露密钥?谁又能保证密钥永远不会泄露?

核心凭证

OAuth2中有3种关键凭证,用于确保授权流程的安全性

  1. 授权码(Authorization Code)

    • 短期有效(几分钟),由授权服务器在用户同意授权后生成。
    • 仅能使用一次,兑换令牌后失效,避免被劫持后重复使用。
  2. 访问令牌(Access Token)

    • 客户端访问资源服务器的"key",包含了授权范围(比如只能访问头像,不能访问手机号)
    • 通常为JWT,资源服务器通过它验证客户端的访问权限。
  3. 刷新令牌(Refresh Token)

    • 长期有效(几天到几个月),用户在Access Token过期后,无需重新授权,直接获取Access Token。

image

Q1:授权服务器生成Code之后,redirect_uri重定向回前端还是后端?
授权服务器生成 Code 后,通过 redirect_uri 首先发送给第三方客户端的前端(浏览器 / APP),再由前端中转到客户端的后端,最终由后端用 Code 交换 Access Token。

Q2:为什么Code一定要重定向回前端,后端不行吗?
可以,但会造成如下几个问题:

  1. 用户授权流程的缺失
    当用户同意授权后,如果直接发给后端。那么用户的前端页面完全不知道授权结果,比如用户在微信登录页授权后,浏览器还停留在微信页面,不知道该跳转回到客户端哪里。授权流程被割裂,对于用户体验不好。
  2. 无法验证客户端的合法性
    如果直接发后端,授权服务器只能通过RedirectUri来判断,但这个地址可能会被伪造,比如攻击者伪装成客户端后端地址,诱导授权服务器把 Code 发给他。HTTPS的中间人攻击也是这个原理。
    而通过前端重定向,「用户的上下文」就是天然的验证:用户是从客户端前端跳转去授权服务器的,授权后跳回客户端前端,相当于用户 “背书” 了这个客户端的合法性,避免了攻击者伪造后端接收 Code 的风险。
  3. 网络可达性问题
    后端地址可能是企业内网,也可能是有防火墙,跳板机,堡垒机等保护。授权服务器根本无法直接访问这些后端接口
    而网页前端天生自带公网IP,授权服务器只需通过 “跳转” 把 Code 交给前端,再由前端中转给后端,完美解决了 “授权服务器找不到客户端后端” 的问题

为什么OAuth2与SSO经常混为一谈?

SSO是一种"业务目标",而OAuth2是实现该目标的常用方案之一。它们是两个不同的概念,既不冲突也不等同,而是 “目标与工具” 的关系。
OAuth2可以实现SSO,但不是SSO的唯一实现方式。还有其它协议,比如SAML2.0,CAS,以及非常轻量化的Cookie共享,Ticket自包含等方案。

它们混淆的根源在于:

  1. 场景高度重叠
    OAuth2最常见的场景就是第三方登录,比如使用微信登录美团,淘宝等第三方客户端。
    在用户的视角下,只要使用微信登录,就能登录多个应用一气呵成,很流畅很润,对于用户最直观的感受就是,这就是SSO。
    image
    在开发者的视角下,对接第三方登录时,市面上90%的方案就是OAuth2协议,久而久之就形成了刻板印象与路径依赖。

  2. 概念边界很模糊,认证与授权往往同时出现
    主流基于OAuth2的SSO方案,不会只做"身份认证",还会同步处理"权限校验"。而OAuth2刚好能同时解决,导致SSO与OAuth2深度绑定,难以拆分理解

我就经常混淆.NET中app.UseAuthentication()与app.UseAuthorization() ,他们两个的单词拼写都很接近,更别说概念了。

两者核心差异

OAuth2的核心是授权,即使不用来做SSO,它也能单独解决"第三方应用访问用户资源"的问题。
SSO的核心是认证,即使不用OAuth2,它也能解决"重复登录"的问题,比如使用JWT形式的Ticket,也能实现SSO,与授权无关。

OAuth2如何勾搭上SSO的?

在文章中,一直强调OAuth2是对资源的管理,好像跟认证没啥关系啊。为什么能扯上关系?
正所谓,弹道也是道,枪法也是法,保时捷也是劫
当今互联网识别用户唯一标识的主流,分别是Email&Phone。
我们可以把这两者当作一种资源去申请,申请到之后,跟自己数据库匹配,如果存在那就直接颁发ticket/cookie,如果不匹配,就自动创建用户并颁发ticket/cookie。 从而以一种曲线救国的方式完成了免密登录。
image

简单DEMO

https://gitee.com/lmy5215006/auth-learning-work
image
image
image

埋了一个彩蛋,再次解释了为什么Code一定要重定向回前端。