Files
QuestionProject/ai_knowledge_base_v2/docs/应用免登录接入说明.md

138 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 千问千答应用免登录接入说明
## 1. 适用场景
学员已经在其他可信应用完成登录,从该应用进入千问千答时,不再重复输入手机号和验证码。
接入应用只能在自己的服务端申请一次性授权码。应用密钥不得写入网页、App 安装包、小程序或公开仓库。
## 2. 准备工作
管理员在千问千答后台的“应用接入”页面完成:
1. 填写千问千答用户端公网地址;
2. 新增接入应用;
3. 保存系统只展示一次的应用密钥;
4. 如需学员从千问千答返回来源应用,配置完整的回跳地址白名单。
5. 选择是否允许自动注册新学员;开启时必须同时选择默认权益版本。
首次免登录时,接入应用必须提供学员在本应用内的稳定用户 ID 和已经由本应用验证过的手机号。手机号仅用于首次匹配千问千答学员,后续以账号绑定为准。
## 3. 申请一次性授权码
接口:
```text
POST /api/integration/sso/ticket
```
请求体示例:
```json
{"externalUserId":"student-10086","verifiedPhone":"13800138000","displayName":"张同学","returnUrl":"https://student.example.com/home"}
```
请求头:
```text
X-App-Id: 后台生成的应用ID
X-Timestamp: 当前 Unix 秒级时间戳
X-Nonce: 每次请求生成的唯一随机字符串长度至少16位
X-Signature: HMAC-SHA256 十六进制签名
```
签名原文:
```text
时间戳 + "\n" + 随机字符串 + "\n" + SHA256(原始请求体字节)
```
使用应用密钥对签名原文执行 HMAC-SHA256输出小写十六进制字符串。必须对实际发送的原始 JSON 字节计算摘要,不要对解析后重新排序的对象签名。
Python 示例:
```python
import hashlib
import hmac
import json
import secrets
import time
body = json.dumps(
{
"externalUserId": "student-10086",
"verifiedPhone": "13800138000",
"displayName": "张同学",
"returnUrl": "https://student.example.com/home",
},
ensure_ascii=False,
separators=(",", ":"),
).encode("utf-8")
timestamp = str(int(time.time()))
nonce = secrets.token_urlsafe(24)
canonical = f"{timestamp}\n{nonce}\n{hashlib.sha256(body).hexdigest()}".encode()
signature = hmac.new(APP_SECRET.encode(), canonical, hashlib.sha256).hexdigest()
```
成功响应:
```json
{
"code": 0,
"message": "success",
"data": {
"code": "一次性授权码",
"expiresInSeconds": 60,
"entryUrl": "https://qa.example.com/?sso_code=一次性授权码"
}
}
```
接入应用收到响应后让浏览器、App WebView 或小程序 WebView 打开 `entryUrl`。授权码只能使用一次60 秒后自动失效。
## 4. 用户匹配规则
- 已经绑定:按“应用 ID + 外部用户 ID”直接找到千问千答学员
- 首次进入:使用已验证手机号匹配现有学员并建立绑定;
- 手机号不在学员名单且应用未开启自动注册:拒绝进入;
- 手机号不在学员名单且应用已开启自动注册:必须同时提供姓名,系统创建学员、分配该应用的默认权益,再建立外部账号绑定;
- 学员已禁用、尚未生效或权益已过期:拒绝进入;
- 同一应用中的一个千问千答学员只能绑定一个外部用户 ID。
绑定错误时,管理员可以在“应用接入 → 账号绑定”中解除绑定,学员下次进入时重新核对手机号。
## 5. 账号与会话数据规则
- 同一手机号只对应一个千问千答学员账号,不会因接入多个应用重复注册;
- 学员的会话、消息、AI 请求和衍生的求助卡/分享稿仍保存在千问千答服务器;
- 会话按登录来源强制隔离:直接登录只能看到直接会话,从应用 A 进入只能看到应用 A 的会话,不能访问应用 B 或直接登录会话;
- 隔离规则由后端根据签名登录态强制执行,不依赖前端传入来源参数;
- 管理员可在“记录审计”按直接访问、第三方应用和具体应用筛选会话。
## 6. 安全规则
- 所有生产接口必须使用 HTTPS
- 应用密钥只保存在接入应用服务端;
- 请求时间戳允许误差不超过 5 分钟;
- `X-Nonce` 在 5 分钟内不得重复;
- `returnUrl` 必须与后台白名单完全匹配;
- Redis 不可用时停止签发和兑换授权码,不降级为长期 Token
- 更新应用密钥后,旧密钥立即失效;
- 停用接入应用后,该应用不能继续申请或兑换登录态;
- 登录成功和失败都会写入登录审计。
## 7. 验收清单
- 已登录来源应用的学员点击后直接进入千问千答;
- 首次进入能按已验证手机号正确绑定;
- 开启自动注册时,新手机号能创建学员并获得指定的默认权益;
- 未开启自动注册时,新手机号仍被拒绝;
- 后续进入不再依赖手机号;
- 同一个授权码第二次兑换失败;
- 错误签名、过期时间戳、重复随机数均被拒绝;
- 非白名单回跳地址被拒绝;
- 禁用或过期学员不能进入;
- 停用应用和更新密钥立即生效;
- 手机号验证码登录仍可正常使用。
- 直接登录、应用 A 和应用 B 各自只能查看、修改和删除本来源会话。