Oauth登录

文章目录

OAuth 登录

OAuth 登录,就是让你通过一个已经有的账号(比如

Google、GitHub、OpenAI),授权另一个应用使用某些功能,而不需要把账号密码告诉那个应用

OAuth 的核心是:用户在官方平台确认授权,第三方应用获得有限权限的 Token,而不是拿到用户密码。

OAuth 是一个授权协议

  • 认证(Authentication):确认你是谁。
  • 授权(Authorization):确认你允许某个应用做什么。
    一、OAuth 是什么?

假设你正在使用一个第三方软件 A,它需要访问你的 GitHub 仓库。

通常有两种方式:

方式一:直接提供账号密码

你把 GitHub 的账号和密码告诉软件 A,软件 A 使用你的账号密码访问 GitHub。

问题是:软件 A 知道了你的密码,不安全。

方式二:使用 OAuth 授权

你不需要告诉软件 A 密码,而是:

  1. 软件 A 让你跳转到 GitHub 官方登录页面。
  2. 你在 GitHub 页面登录账号。
  3. GitHub 询问你:「是否允许软件 A 访问你的某些仓库?」
  4. 你点击同意。
  5. GitHub 给软件 A 一个访问凭证(Access Token)。
  6. 软件 A 使用这个凭证访问你授权的 GitHub 资源。 关键区别:软件 A 拿到的是访问凭证,不是你的 GitHub 密码。

OAuth登录完整流程

OAuth 登录和普通登录有什么区别?

举例

OAuth 授权码模式(Authorization Code Flow)的核心就是:

MyAgent 先告诉 OpenAI 自己是哪个应用、想要什么权限、授权后回到哪里 → 用户在 OpenAI 登录并同意授权 → 浏览器把授权码交给 MyAgent → MyAgent 使用授权码和 PKCE 验证材料换取 Access Token → MyAgent 使用 Token 调用获准的服务->Token过期后用 Refresh Token 换新的
用一个完整场景解释: 你开发了一个 MyAgent,用户希望通过自己的 ChatGPT

账号登录,让 MyAgent 使用获得授权的 GPT 模型。(MyAgent 想使用你的 OpenAI 账号,但它不能直接拿你的账号密码,所以它要先去 OpenAI 申请授权。)

OAuth 中的四个角色

  • 用户(Resource Owner)

    就是拥有 ChatGPT 账号的你,决定是否允许 MyAgent 获得访问权限。

  • 客户端(Client)

    就是你开发的 MyAgent。它希望代表用户调用获得授权的服务。

  • 授权服务器(Authorization Server)

    负责用户登录、确认授权、签发授权码及 Token。

  • 资源服务器(Resource Server)

    真正提供 API 服务,例如执行获得授权的 GPT 模型请求。它验证 Access Token 及权限。

整个流程

第一步:MyAgent 发起授权请求

假设你在 MyAgent 中点击「使用 OpenAI 登录」。 MyAgent 就会让浏览器打开: 前面的地址

https://auth.example.com/authorize 是 OpenAI 提供的授权入口(这里是虚构的)。

后面的参数,就是 MyAgent 告诉 OpenAI 的信息。

点击「Login with OpenAI」后,软件让浏览器 打开OpenAI 的 OAuth 授权地址。

例如(以下全部为虚构地址和示例参数):

复制代码
https://auth.example.com/authorize
  ?response_type=code
  &client_id=myagent123
  &redirect_uri=http://127.0.0.1:3000/callback
  &scope=model.access
  &state=xyz789
  &code_challenge=HASH_VALUE
  &code_challenge_method=S256
参数 作用
response_type=code 告诉服务商我要使用授权码模式
client_id 告诉服务商申请授权的是哪个应用
redirect_uri 授权完成后,浏览器应该跳回哪个地址
scope 申请哪些访问权限
state 防止别人伪造授权回调
code_challenge PKCE 验证材料,防止授权码被别人冒用
code_challenge_method=S256 这个结果是通过 SHA-256 计算的

这里有个关键点: 用户还没登录,MyAgent 就已经告诉服务商"我是谁"和"授权完成后该返回哪里"。服务商会根据已注册或支持的客户端信息检查 client_id 和回调地址
response_type=code

意思是:

「OpenAI,我希望你采用授权码模式。用户同意授权后,先给我一个授权码。」

为什么不直接给 Access Token?

因为授权码可以先交给 MyAgent,再由 MyAgent 通过另外一次请求兑换 Access Token,并完成相应的安全验证。

你暂时记住:

  • code:临时授权码。
  • access_token:真正用于访问 API 的凭证。
    client_id=myagent123

这是最重要的参数之一。

假设你开发了一个叫 MyAgent 的应用。

你想让 MyAgent 支持「使用 OpenAI 登录」。

那么通常需要先到 OpenAI 的开发者平台注册你的应用(这里假设平台支持这种注册方式)。

注册后,OpenAI 给你一个编号:

应用名称:MyAgent

应用编号:myagent123

这个编号就是 client_id。

以后 MyAgent 发起授权请求时,带上:

client_id=myagent123

OpenAI 收到请求就知道:

「哦,这是编号为 myagent123 的应用在申请授权。」

注意两点:

第一,client_id 是应用的编号,不是你个人账号的编号。

第二,client_id 不属于密码。 任何人都可能看到这个编号,它不能单独证明请求方一定是合法应用。
redirect_uri=http://127.0.0.1:3000/callback

这个参数告诉 OpenAI:

「用户完成授权以后,请让浏览器跳转到这个地址。」

/callback

是 MyAgent 专门用来接收授权结果的路径。

假设 MyAgent 在你的电脑上启动了一个本地服务,监听 3000 端口。

当你完成登录和授权后,OpenAI 就让浏览器跳转到:

http://127.0.0.1:3000/callback?code=abc123

这样,浏览器就会将授权码送到 MyAgent 的本地服务。


scope=model.access

意思是:

「我想申请哪些权限?」

举个例子:

假设 OpenAI 提供以下权限:

权限(假设) 作用

model.access 调用 AI 模型

profile.read 读取用户基本信息

files.read 读取用户文件

MyAgent 如果只需要调用 AI 模型,就可以申请:

scope=model.access

当然,这些权限名称都是我们假设的。实际有哪些权限,取决于服务商。
state=xyz789

这个参数是为了防止别人伪造授权回调。

假设 MyAgent 发起登录时,随机生成了:

state=xyz789

MyAgent 会把这个值保存在本地。

当 OpenAI 授权完成后,浏览器跳转到:

http://127.0.0.1:3000/callback

?code=abc123

&state=xyz789

MyAgent 收到后就会检查:

自己保存的 state:xyz789

收到的 state: xyz789

两者相同 ✓

如果不一样,就拒绝这次回调。

你可以把 state 理解为 MyAgent 给这一次登录申请设置的随机编号。

注意:真正使用时,每次登录都应该重新随机生成,而不是一直使用 xyz789。
code_challenge=HASH_VALUE

这个参数涉及一个叫 PKCE 的安全机制。

你可以先理解一个问题:

假设 MyAgent 完成授权后,OpenAI 返回:

code=abc123

如果这个授权码被别人偷走了怎么办?

为了降低这个风险,MyAgent 会在发起登录之前做两件事。

第一步:生成一个随机秘密值。

code_verifier = 一长串随机字符

这个值保存在 MyAgent 本地,不会在最初的授权请求中发送出去。

第二步:根据这个秘密值计算一个结果。

code_challenge = SHA256(code_verifier)

这里为方便理解省略了 Base64URL 编码步骤。

MyAgent 把计算结果 code_challenge 告诉 OpenAI。

等到 MyAgent 拿着授权码去换 Access Token 时,还必须提供最初那个 code_verifier。

OpenAI 就能检查:

「这个人提供的秘密值,是否能够计算出之前提交的 code_challenge?」

如果一致,才可能继续发放 Token。

因此,别人即使偷走授权码,如果不知道 code_verifier,一般也无法成功兑换 Access Token。
code_challenge_method=S256

这个参数比较简单。

它告诉 OpenAI:

「我是用 SHA-256 计算 code_challenge 的。」

实际计算方式是:

S256 就是这种计算方式的名称

MyAgent 还没登录,OpenAI 怎么就知道它是谁?

这里其实存在两个不同的身份:

  • 应用身份:MyAgent 是哪个应用?
  • 用户身份:当前是谁在使用 MyAgent?
    这两个身份的确定时间不同。

为什么点击登录会打开浏览器?

因为需要通过 OpenAI 官方控制的网页验证你的身份,并完成授权。

服务商通常通过网页让用户登录和确认授权,所以需要浏览器访问这个网址。

登录界面就是 OpenAI 自己开发的前端页面,浏览器负责把这个页面展示出来。

浏览器输入网址,发送的是什么请求?get

假设你在浏览器地址栏输入:

https://example.com/login 然后按回车。

浏览器通常会自动发送一个 HTTP GET请求:

GET /login HTTP/1.1

Host: example.com

这个请求被发送到 example.com 的服务器。

浏览器通过 GET 向服务器请求网页资源,获取 HTML、CSS、JavaScript 后,由浏览器运行这些前端代码并显示界面。

Nginx 本身没有前端代码,但你可以把打包好的前端代码放在服务器的某个目录下,然后配置 Nginx 去这个目录查找文件。

Nginx 不需要懂 Vue、React,它只需要知道:前端文件存放在哪里,收到请求后应该返回哪个文件。

在 Vue、React 前后端分离架构中,前端代码本身不会直接接收浏览器发出的 HTTP GET 请求。

你可以这样理解:

  • Nginx:接收浏览器发送的 GET 请求。
  • 前端代码(Vue、React):由浏览器下载并执行,负责显示页面、处理用户交互和切换路由。




第二步:用户在服务商页面登录

浏览器打开刚才的授权链接。

你看到的是服务商自己的登录页面,而不是 MyAgent 收集账号密码。

用户完成登录后,服务商知道:

登录的用户:张三

申请授权的应用:MyAgent

申请的权限:model.access(示例)

如果用户同意,服务商就会记录这次授权,并签发一个临时授权码。

这里要注意:登录成功不一定等于授权成功。用户可能拒绝授权,服务商也可能因策略限制而拒绝请求。

第三步:生成授权码,并通过回调返回

假设服务商生成:

Authorization Code = ABC123

它怎么把授权码发给 MyAgent?

答案就是Callback(回调)。

在 OAuth 授权码模式中,授权服务器通常给浏览器返回一个HTTP 重定向响应:

HTTP/1.1 302 Found

Location: http://127.0.0.1:3000/callback?code=ABC123\&state=xyz789

浏览器看到 Location,就自动访问这个地址。

注意:

不是服务商服务器直接给 MyAgent 发一条 TCP消息,而是浏览器按照重定向地址去访问 MyAgent。 如果 MyAgent 在你的电脑上运行,并监听:

127.0.0.1:3000

那么浏览器向这个本地端口发送 HTTP 请求,MyAgent 就可以收到: code = ABC123 state = xyz789

所以回调的本质就是: 授权服务器通知浏览器跳转到应用提前指定的地址,并通过这次跳转把授权结果带回来。

第四步:为什么不直接返回 Access Token?

这是整个 OAuth 设计最重要的安全思想。 假设服务商直接在浏览器跳转 URL 中返回 Access Token:

http://127.0.0.1:3000/callback

?access_token=SECRET_TOKEN 那么一旦这个 Token 因浏览器历史、日志、恶意软件或其他渠道泄漏,攻击者就可能直接拿去请求 API。 所以授权码模式采用两次交换:

第五步:MyAgent 使用授权码换 Token

MyAgent 接收到授权码后,会直接向服务商的 Token Endpoint 发送 HTTPS 请求。

示例:

复制代码
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id=myagent123&
code=ABC123&
redirect_uri=http://127.0.0.1:3000/callback&
code_verifier=ORIGINAL_RANDOM_SECRET

其中最重要的是: code=ABC123:证明 MyAgent 已经通过前面的授权流程拿到了授权码。 code_verifier:PKCE

使用的原始随机秘密,证明兑换授权码的客户端掌握了发起授权请求时生成的验证材料。

code_verifier:证明兑换授权码的一方掌握最初生成的 PKCE 秘密值。

第一次用 code_challenge 提前设定验证条件,第二次用 code_verifier 证明自己掌握原始秘密,两次匹配成功,才能通过 PKCE 验证。

对于需要客户端密钥的机密客户端,还需要相应的客户端认证,例如

client_secret。本地 CLI 这种公开客户端通常不能安全地保存一个固定客户端密钥,因此经常使用 PKCE。PKCE 全称是 Proof Key for Code Exchange,中文可以理解为"授权码交换证明机制"。

服务商检查通过后,返回类似: { "access_token": "ACCESS_123", "refresh_token":

"REFRESH_456", "token_type": "Bearer", "expires_in": 3600 }

以上值都只是示例;Refresh Token 不保证每次都下发。 这四个字段分别表示:

字段 意思
access_token 真正调用受保护 API 使用的凭证
refresh_token 用来获取新 Access Token 的凭证
token_type Token 的使用类型,示例是 Bearer
expires_in Access Token 的有效期(单位:秒)

至此,MyAgent 才真正拿到了可用于获授权 API 请求的 Access Token

四、为什么还需要 Refresh Token?

PKCE 又是什么?为什么有授权码还不够?

小测试

Authorization Code 是一次性兑换凭证,Callback 是让授权结果回到应用的机制,Access Token 是访问服务的凭证,Refresh Token 是更新访问凭证的工具,而 PKCE 是保证授权码兑换过程安全的重要机制。

相关推荐
我qq不是4515165210 分钟前
WorkBuddy下载体验
人工智能·经验分享·ai·workbuddy
IT_陈寒1 小时前
Redis雪崩把我坑惨了,这是5年经验的教训
前端·人工智能·后端
心祭丫丫1 小时前
【每天一个 Python 小案例17】Python 实现通讯录
开发语言·人工智能·笔记·python·学习
海螺_AIHCC1 小时前
LLM 返回的 JSON 十次坏三次,别急着骂模型——60 行容错解析器先兜住(附可运行代码)
人工智能
露天赏雪2 小时前
第3篇:Sentinel熔断降级实战:大模型接口抖动时的服务兜底方案
java·开发语言·人工智能·spring boot·spring·servlet·sentinel
lisw052 小时前
理解推理大语言模型的可监控性!
人工智能·语言模型·自然语言处理
天天被压力2 小时前
【A股分钟级高频数据完全手册 #06】北交所分钟级数据接口:京市股票Pro版最新分时
java·人工智能·python
在所不辞兄2 小时前
为什么学习率预热(warmup)能显著改善Transformer等大模型的训练稳定性?
人工智能·深度学习·神经网络·机器学习·智能仿真
天天被压力2 小时前
【A股分钟级高频数据完全手册 #05】指数历史分钟数据接口:Pro版沪深指数分时回放
java·人工智能·python