认证与授权
认证与授权 是 RTC Agent 的安全基石。用户通过 OAuth2 授权码模式登录,系统使用双令牌(Access + Refresh)维持会话,支持多设备并行登录,令牌自动刷新——用户只需登录一次,即可长期使用。
| 步骤 | 说明 |
|---|---|
| 1 | 用户点击登录按钮,弹出登录对话框 |
| 2 | 对话框通过 iframe 展示 OAuth2 Provider 的授权页面 |
| 3 | 用户在 Provider 页面完成授权(如 GitHub、Google 等) |
| 4 | 授权成功后,系统获取授权码并换取令牌 |
| 5 | 令牌存储到浏览器本地,登录完成 |
💡 设计原则:登录流程完全委托给 OAuth2 Provider——RTC Agent 不接触用户密码,安全由 Provider 保障。
| 令牌 | 有效期 | 用途 | 存储方式 |
|---|---|---|---|
| 🔑 Access Token | 1 小时 | 访问 API 和 WebSocket | 明文(短有效期,风险可控) |
| 🔄 Refresh Token | 30 天 | 刷新 Access Token | 仅存哈希值(明文一次性返回后丢弃) |
📌 安全要点:Refresh Token 的明文只在签发时返回一次,之后服务端仅保存哈希。即使浏览器存储被泄露,攻击者也无法长期冒充用户。
系统在多个时机自动刷新令牌,用户完全无感知:
| 触发时机 | 说明 |
|---|---|
| ⏱️ 令牌即将过期 | 到期前 5 分钟自动刷新,避免请求中断 |
| 📱 页面切回前台 | 从后台切回时检查令牌状态,过期则立即刷新 |
| 🔌 建立 WebSocket | 连接时按需刷新令牌,确保令牌有效 |
💡 刷新失败不会让用户停留在”半死不活”的状态——系统会直接退出登录,引导用户重新认证。
| 概念 | 说明 |
|---|---|
| 🔖 设备 ID | 浏览器唯一标识(UUID),首次访问时自动生成 |
| 📛 设备名 | 根据操作系统自动推断(如”Mac”、“Windows PC”、“Linux PC”) |
| 🔀 多设备 | 同一用户可在多个设备独立登录,互不影响 |
📌 每个设备的令牌相互独立——在设备 A 上退出登录不会影响设备 B 的会话。
WebSocket 认证
Section titled “WebSocket 认证”| 阶段 | 说明 |
|---|---|
| 🔗 建连 | WebSocket 连接时携带 Access Token 进行认证 |
| ✅ 验证 | 服务端校验令牌有效性,无效则拒绝连接 |
| 📡 订阅 | 认证通过后订阅用户专属频道,接收实时消息 |
| 🔁 断线 | 连接断开后需重新认证,确保安全性 |
💡 频道隔离:每个用户只能接收自己频道内的消息,无法访问他人数据。
| 约束 | 机制 | 目的 |
|---|---|---|
| 🛡️ CSRF 防护 | OAuth2 授权时使用 state 参数 | 防止跨站请求伪造攻击 |
| 🏷️ 频道隔离 | 用户只能订阅自己的专属频道 | 防止数据泄露和越权访问 |
| 💾 令牌存储 | 令牌仅存储在浏览器本地 | 不传输到第三方,降低泄露风险 |
| 🔑 刷新令牌 | 明文一次性返回,服务端仅存哈希 | 即使存储泄露也无法长期使用 |
| 场景 | 用户看到的行为 |
|---|---|
| ❌ 授权失败 | 登录对话框显示错误信息,可点击重试 |
| ⏱️ 令牌过期且刷新失败 | 自动退出登录,显示登录页面 |
| 🔌 WebSocket 认证失败 | 连接断开,提示用户重新登录 |
- Web Component API — 了解如何通过
<rtc-agent>组件集成 RTC Agent - Function 注册指南 — 注册自定义函数扩展 AI 能力
- 核心协议 RTC — 了解 Remote Tool Calling 的完整生命周期
开发者接入指南
Section titled “开发者接入指南”RTC Agent Server 本身是 OAuth2 消费方——它需要连接一个 OAuth2 提供方来完成用户认证。开发环境内置了 mock-oauth2 作为示例提供方;生产部署时,你需要提供自己的 OAuth2 服务。
💡 RTC Agent Server 负责签发 JWT 令牌和管理设备;你的 OAuth2 服务只负责验证用户身份并返回用户信息。
需要实现的接口
Section titled “需要实现的接口”你的 OAuth2 服务只需实现 2 个端点:
端点 1:授权页面 — GET /oauth2/authorize
Section titled “端点 1:授权页面 — GET /oauth2/authorize”浏览器直接访问(通过 iframe 加载),用于展示登录/授权 UI。
请求(RTC Agent Server 拼接后由浏览器访问):
GET /oauth2/authorize?state=<hex>&client_id=<id>&redirect_uri=<uri>| 参数 | 说明 |
|---|---|
state | 防 CSRF 随机串,必须原样传回 |
client_id | 客户端标识 |
redirect_uri | 授权成功后的回调地址 |
行为要求:
- 展示登录/授权页面(可以是你的现有登录系统)
- 用户授权成功后,生成一个短期、一次性的授权码(code)
- HTTP 302 重定向到
redirect_uri,query string 中携带code和state:
Location: <redirect_uri>?code=<code>&state=<state>页面约束:
- 页面会在 iframe 中加载,不能设置
X-Frame-Options: DENY或限制性的Content-Security-Policy: frame-ancestors - Content-Type 为
text/html; charset=utf-8
端点 2:代码交换 — POST /oauth2/token/exchange
Section titled “端点 2:代码交换 — POST /oauth2/token/exchange”RTC Agent Server 服务端直接调用(server-to-server),用授权码换取用户身份信息。
请求:
POST /oauth2/token/exchangeContent-Type: application/x-www-form-urlencodedAccept: application/json
client_id=<id>&client_secret=<secret>&code=<code>&redirect_uri=<uri>成功响应(200):
{ "provider_user_id": "user-12345", "username": "张三", "email": "zhangsan@example.com", "avatar_url": "https://example.com/avatar.png"}| 字段 | 必填 | 说明 |
|---|---|---|
provider_user_id | ✅ | 用户在你系统中的稳定唯一标识,同一用户必须始终返回相同值 |
username | 可选 | 显示名称 |
email | 可选 | 邮箱 |
avatar_url | 可选 | 头像 URL |
错误响应:
{ "error": "invalid_client", "error_description": "client_id 或 client_secret 错误"}| HTTP 状态码 | error 值 | 含义 |
|---|---|---|
| 400 | invalid_request | 缺少或非法参数 |
| 400 | invalid_grant | 授权码无效、已使用或已过期 |
| 401 | invalid_client | 客户端凭证错误 |
| 500 | server_error | 服务端内部错误 |
| 约束 | 说明 |
|---|---|
| 一次性 | 同一 code 只能交换一次 |
| 短期有效 | 建议 10 分钟内过期 |
| 绑定用户 | code 必须关联到已认证的用户身份 |
不需要实现的部分
Section titled “不需要实现的部分”- ❌ 不需要签发 access_token / refresh_token — RTC Agent Server 自己签发 JWT
- ❌ 不需要实现标准 OAuth2 的
/token端点 —/oauth2/token/exchange本质是用户信息接口 - ❌ 不需要支持 scope、PKCE 等扩展
配置 RTC Agent Server
Section titled “配置 RTC Agent Server”实现好你的 OAuth2 服务后,在 Server 配置中指向它:
providers: mock: enabled: true url: "https://your-oauth-server.com" # 你的 OAuth2 服务地址 client_id: "your-client-id" # 与你的服务约定的 client_id client_secret: "your-client-secret" # 与你的服务约定的 client_secret⚠️
providers.mock的mock是 provider 名称(不是”测试用”的意思)。Server 会将{url}/oauth2/authorize和{url}/oauth2/token/exchange拼接为两个端点地址。如果你的服务路径不同,需要扩展BuildProviderClients或保持路径一致。