
这张图想表达的是:OAuth 2.0 不是“登录协议”,而是一个“授权协议”——让你在不把密码交给第三方应用的前提下,把你在某个平台上的一部分权限(数据/操作)“临时借给”另一个应用。
1) OAuth 2.0 解决什么问题?(一句话)
你想用「某网站/某App」去访问你在「谷歌/微信/GitHub」上的数据或能力,但你不想把账号密码给那个网站/App。OAuth 2.0 就是这个“安全借权限”的标准做法。
2) 图里说的 3 个角色(最关键)
图里把 OAuth 拆成 3 个实体:
-
User(用户 / Resource Owner)
数据主人(比如你:你的邮箱、头像、联系人、云盘文件…) -
Server(第三方应用 / Client)
你正在使用的那个服务(比如某个网站想读取你的 Google 资料) -
IdP(身份提供商 / Authorization Server)
真正管你身份、能发放授权的“平台”(比如 Google、GitHub、Microsoft…)它负责:让你登录、让你点“同意授权”、然后发令牌给第三方应用
3) 核心思想:不给密码,给“令牌”(Token)
-
密码(Password):相当于你家钥匙 + 全权限,给出去就麻烦了。
-
访问令牌(Access Token):相当于“临时门禁卡”,只允许做被授权的事,并且通常有过期时间。
-
(常见还有)刷新令牌(Refresh Token):Access Token 过期后,用它去换新的 Access Token(不必让你反复点同意/登录)。
另外还有个重要概念:Scope(授权范围)
比如:只允许读头像 profile,不允许读邮件;只允许读,不允许写。
4) 图右下的重点:Authorization Code Flow(授权码流程)
这是 OAuth 2.0 最经典、最常用的流程(也是现在最推荐的主流之一)。
按图里的“浏览器三方对话”翻译成通俗步骤:
-
你在第三方应用里点:“用 Google 授权访问我的数据”
-
第三方应用把你重定向到 Google(IdP):
“这位用户要授权我访问哪些权限(scopes)” -
你在 Google 页面登录 + 看清楚权限提示 + 点同意
-
Google 不把 Token 直接给浏览器里的第三方应用,而是先给一个:Authorization Code(授权码)
-
第三方应用(服务器端)拿这个授权码去找 Google 换取 Access Token(以及可能的 Refresh Token)
-
第三方应用拿 Access Token 去调用资源接口:
比如GET /my-data,最终把数据返回给你
你全程只把密码输入给 Google(IdP),第三方应用根本拿不到你的密码 —— 这就是 OAuth 最核心的安全点。
5) 图里列的 “4 种 OAuth Flow” 是什么(以及现在用不用)
图中列了 4 种常见授权方式:
-
Authorization Code(授权码) ✅ 主流推荐
-
现在通常搭配 PKCE(尤其移动端/桌面端/SPA)更安全
-
-
Client Credentials(客户端凭证) ✅ 常用于“服务访问服务”
-
没有用户参与,比如后端服务调用后端服务(机器对机器)
-
-
Implicit(隐式) ⚠️ 现在基本不推荐/逐渐弃用
-
因为把 token 直接暴露在前端环境里,风险更高
-
-
Resource Owner Password(密码模式) ❌ 基本不推荐/已被淘汰思路
-
让用户把密码交给第三方应用,等于回到老问题
-
6) 很多人会混淆的点:OAuth ≠ 登录
-
OAuth 2.0 解决的是“授权(Authorization)”:允许第三方做哪些事。
-
如果你想实现“用 Google 登录”(知道“你是谁”),通常会用:OpenID Connect(OIDC)
OIDC 是建立在 OAuth 2.0 之上的“身份层”,会返回 ID Token(告诉你用户身份信息)。
7) 用一个生活类比收尾
-
你(User):房主
-
Google(IdP):物业/门禁系统
-
第三方应用(Server/Client):维修工
-
OAuth 授权:你去物业那边刷脸确认“允许维修工进客厅修灯但别进卧室”,物业给维修工一张只开客厅门、半小时有效的门禁卡(token)。维修工从此不用你家钥匙(密码)。
OAuth 2.0 代码示例
OAuth 2.0 有多种授权流程(Grant Types),下面我用 Python 语言提供几个常见流程的代码示例。这些示例基于 Requests-OAuthlib 库(一个流行的 Python OAuth 库),假设你已经安装了它(pip install requests-oauthlib)。代码中会使用占位符如 your_client_id,在实际使用时需要替换为你的客户端 ID、密钥等(从服务提供商如 Google、GitHub 获取)。
我将重点解释 Authorization Code Grant Flow(授权码流程),这是最安全、最常用的流程,适合 Web 应用。然后简要提供其他流程的示例。每个示例包括导入、设置和步骤说明。
1. 授权码授予流程(授权码流程)
这个流程涉及用户重定向到授权服务器登录,然后回调获取令牌。适合需要用户交互的场景,比如用 Google 登录你的 App。
步骤说明:
- 创建 OAuth2Session 对象。
- 生成授权 URL,让用户访问并授权。
- 用户授权后,输入回调 URL(实际 Web App 中用服务器处理)。
- 用授权响应换取访问令牌。
- 用令牌访问受保护的资源。
# 导入必要的库
from requests_oauthlib import OAuth2Session
# 配置你的客户端信息(从服务提供商获取)
client_id = 'your_client_id' # 你的客户端 ID
client_secret = 'your_client_secret' # 你的客户端密钥
redirect_uri = 'https://your.callback/uri' # 你的回调 URL
# 定义权限范围(scope),根据提供商调整
scope = [
'https://www.googleapis.com/auth/userinfo.email', # 示例:Google 的 email 权限
'https://www.googleapis.com/auth/userinfo.profile' # 示例:Google 的 profile 权限
]
# 创建 OAuth2Session 对象
oauth = OAuth2Session(
client_id,
redirect_uri=redirect_uri,
scope=scope
)
# 生成授权 URL(authorization_url)和状态(state,用于防 CSRF)
authorization_url, state = oauth.authorization_url(
'https://accounts.google.com/o/oauth2/auth', # 示例:Google 的授权端点
access_type="offline", # 请求离线访问(可选)
prompt="select_account" # 提示用户选择账号(可选)
)
# 提示用户访问 URL 并授权(在实际 Web App 中,重定向用户)
print(f'请访问 {
authorization_url} 并授权访问。')
# 用户授权后,输入完整的回调 URL(实际中由服务器捕获)
authorization_response = input('请输入完整的回调 URL: ')
# 用授权响应换取令牌
token = oauth.fetch_token(
'https://accounts.google.com/o/oauth2/token', # 示例:Google 的令牌端点
authorization_response=authorization_response,
client_secret=client_secret
)
# 现在可以用令牌访问受保护的 API
r = oauth.get('https://www.googleapis.com/oauth2/v1/userinfo') # 示例:获取用户信息
print(r.json()) # 输出响应
注意:这个是命令行版本,用于演示。在真实 Web 应用(如 Flask/Django)中,你需要处理 HTTP 重定向和回调路由。令牌(token)包含 access_token,可用于后续 API 调用。
2. Client Credentials Grant Flow(客户端凭证流程)
这个流程不涉及用户,直接用客户端凭证换取令牌。适合服务器间通信或后台服务。
步骤说明:
- 创建 BackendApplicationClient。
- 用客户端 ID 和密钥直接获取令牌。
- 无需用户交互。
# 导入必要的库
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
# 配置客户端信息
client_id = 'your_client_id'
client_secret = 'your_client_secret'
# 创建客户端
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
# 获取令牌
token = oauth.fetch_token(
token_url='https://provider.com/oauth2/token', # 替换为实际令牌端点
client_id=client_id,
client_secret=client_secret
)
# 用令牌访问 API
r = oauth.get('https://provider.com/protected-resource')
print(r.json())
3397





被折叠的 条评论
为什么被折叠?



