Files
im_server/docs/IM-青少年模式前后端对接文档.md
T

387 lines
9.3 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.
# IM 青少年模式前后端对接文档
## 1. 基本约定
青少年模式相关接口均为登录后接口。客户端需要携带用户登录 token、普通 API Key 和协议版本头。
公共 Header:
```http
Authorization: Bearer <access_token>
X-MeetingIM-Auth: Bearer <access_token>
X-MeetingIM-APIKey: <api_key>
X-IM-Schema: 1
X-Request-ID: <uuid>
X-Tenant-Code: default
```
所有写接口还需要携带:
```http
Idempotency-Key: <uuid>
```
测试环境验证码固定为 `123456`。`action_token` 为 5 分钟有效、单次消费,只能用于指定动作,不能在多个接口之间重复使用。
当前默认策略项为 `night_quiet`、`content_filter`、`payment_guard` 三条。现阶段后端已完成状态持久化、开启/关闭校验和策略返回;`night_quiet` 已接入音视频呼叫发起限制,`content_filter` 已接入消息发送前内容安全审核,响应中的这两项 `restriction_items[].enforced=true`。`payment_guard` 当前仍为预留项,`enforced=false`。
## 2. 开启青少年模式
### 2.1 查询当前状态
```http
GET /v1/im/settings/youth-mode
```
成功响应:
```json
{
"code": 0,
"data": {
"enabled": false,
"policy_version": 1,
"restrictions": ["night_quiet", "content_filter", "payment_guard"],
"restriction_items": [
{
"code": "night_quiet",
"title": "深夜免打扰",
"description": "夜间减少消息提醒打扰,帮助用户保持健康作息。",
"enforced": true
},
{
"code": "content_filter",
"title": "内容过滤",
"description": "对不适合青少年的内容进行识别和限制展示。",
"enforced": true
},
{
"code": "payment_guard",
"title": "支付守护",
"description": "限制或确认支付、充值等敏感消费行为。",
"enforced": false
}
],
"password_set": false,
"can_enable": false,
"updated_at": "2026-08-20T09:00:00Z"
}
}
```
前端优先使用 `restriction_items` 渲染开启确认页,`restrictions` 保留为兼容旧客户端的 code 数组。最终开启时需要提交用户确认过的 `policy_version`。
### 2.2 发起短信身份验证
```http
POST /v1/im/security/challenges
```
请求体:
```json
{
"scene": "set_independent_password",
"channel": "sms"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"challenge_id": "sec_chg_1",
"phone_mask": "+861****000",
"expires_in_seconds": 300,
"resend_after_seconds": 60
}
}
```
手机号由服务端从当前登录用户读取,客户端不提交目标手机号。
### 2.3 校验短信验证码
```http
POST /v1/im/security/challenges/{challenge_id}/verify
```
请求体:
```json
{
"code": "123456"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"action": "set_independent_password",
"action_token": "set_password_token",
"expires_at": "2026-08-20T09:05:00Z"
}
}
```
这里拿到的 `action_token` 只用于设置独立密码,不能直接用于开启青少年模式。
### 2.4 设置独立密码
```http
POST /v1/im/settings/independent-password
```
请求体:
```json
{
"password": "6439",
"purpose": "youth_mode",
"action_token": "set_password_token"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"status": "ok",
"password_set": true,
"purpose": "youth_mode",
"enable_action_token": "enable_token",
"enable_action_expires_at": "2026-08-20T09:05:00Z",
"next_action": "enable_youth_mode"
}
}
```
服务端会消费 `set_password_token`,并返回新的 `enable_action_token`。前端下一步必须使用 `enable_action_token`,不要复用 `set_password_token`。
独立密码规则:
- 必须是 4 位数字。
- 不能是明显连续或重复组合。
- 服务端只保存强哈希,不返回明文密码。
- 前端离开页面后应清空输入内容,不落普通存储。
### 2.5 开启青少年模式
```http
POST /v1/im/settings/youth-mode/enable
```
请求体:
```json
{
"policy_version": 1,
"action_token": "enable_token"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"enabled": true,
"policy_version": 1,
"password_set": true,
"restrictions": ["night_quiet", "content_filter", "payment_guard"],
"restriction_items": [
{
"code": "night_quiet",
"title": "深夜免打扰",
"description": "夜间减少消息提醒打扰,帮助用户保持健康作息。",
"enforced": true
},
{
"code": "content_filter",
"title": "内容过滤",
"description": "对不适合青少年的内容进行识别和限制展示。",
"enforced": true
},
{
"code": "payment_guard",
"title": "支付守护",
"description": "限制或确认支付、充值等敏感消费行为。",
"enforced": false
}
],
"updated_at": "2026-08-20T09:00:00Z"
}
}
```
开启成功后,客户端应刷新本地设置页和 `bootstrap` 缓存。服务端会持久化状态,前端不能只依赖本地标志位。
## 3. 关闭青少年模式
### 3.1 校验独立密码
```http
POST /v1/im/settings/independent-password/verify
```
请求体:
```json
{
"password": "6439",
"purpose": "youth_mode",
"action": "close_youth_mode"
}
```
成功响应:
```json
{
"code": 0,
"data": {
"action": "close_youth_mode",
"action_token": "close_token",
"expires_at": "2026-08-20T09:05:00Z"
}
}
```
### 3.2 关闭模式
```http
POST /v1/im/settings/youth-mode/disable
X-Action-Token: close_token
```
请求体:
```json
{}
```
成功响应:
```json
{
"code": 0,
"data": {
"enabled": false,
"policy_version": 1,
"password_set": true,
"updated_at": "2026-08-20T09:00:00Z"
}
}
```
关闭接口的 `action_token` 通过 Header `X-Action-Token` 传递,不放在 Body 中。
## 4. Token 使用规则
| 来源 | action | 用途 | 传递方式 | 是否单次消费 |
| --- | --- | --- | --- | --- |
| `security/challenges/{id}/verify` | `set_independent_password` | 设置独立密码 | Body `action_token` | 是 |
| `independent-password` | `enable_youth_mode` | 开启青少年模式 | Body `action_token` | 是 |
| `independent-password/verify` | `close_youth_mode` | 关闭青少年模式 | Header `X-Action-Token` | 是 |
常见错误:
- `ACTION_TOKEN_INVALID`:token 已消费、过期、action 不匹配、target 不匹配或用户不匹配。
- `CODE_INVALID`:短信验证码错误。
- `CHALLENGE_EXPIRED`:短信 challenge 已过期。
- `TOO_MANY_ATTEMPTS`:独立密码或验证码错误次数过多。
- `VERIFICATION_RATE_LIMITED`:发码过于频繁,按 `retry_after_seconds` 倒计时。
## 5. curl 示例
开启流程:
```bash
curl -sS 'https://api.118im.com/v1/im/security/challenges' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access_token>' \
-H 'X-MeetingIM-Auth: Bearer <access_token>' \
-H 'X-MeetingIM-APIKey: <api_key>' \
-H 'X-IM-Schema: 1' \
-H 'X-Tenant-Code: default' \
-H 'X-Request-ID: <uuid>' \
-H 'Idempotency-Key: <uuid>' \
--data '{"scene":"set_independent_password","channel":"sms"}'
```
```bash
curl -sS 'https://api.118im.com/v1/im/security/challenges/<challenge_id>/verify' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access_token>' \
-H 'X-MeetingIM-Auth: Bearer <access_token>' \
-H 'X-MeetingIM-APIKey: <api_key>' \
-H 'X-IM-Schema: 1' \
-H 'X-Tenant-Code: default' \
-H 'X-Request-ID: <uuid>' \
-H 'Idempotency-Key: <uuid>' \
--data '{"code":"123456"}'
```
```bash
curl -sS 'https://api.118im.com/v1/im/settings/independent-password' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access_token>' \
-H 'X-MeetingIM-Auth: Bearer <access_token>' \
-H 'X-MeetingIM-APIKey: <api_key>' \
-H 'X-IM-Schema: 1' \
-H 'X-Tenant-Code: default' \
-H 'X-Request-ID: <uuid>' \
-H 'Idempotency-Key: <uuid>' \
--data '{"password":"6439","purpose":"youth_mode","action_token":"<set_password_token>"}'
```
```bash
curl -sS 'https://api.118im.com/v1/im/settings/youth-mode/enable' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access_token>' \
-H 'X-MeetingIM-Auth: Bearer <access_token>' \
-H 'X-MeetingIM-APIKey: <api_key>' \
-H 'X-IM-Schema: 1' \
-H 'X-Tenant-Code: default' \
-H 'X-Request-ID: <uuid>' \
-H 'Idempotency-Key: <uuid>' \
--data '{"policy_version":1,"action_token":"<enable_action_token>"}'
```
关闭流程:
```bash
curl -sS 'https://api.118im.com/v1/im/settings/independent-password/verify' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access_token>' \
-H 'X-MeetingIM-Auth: Bearer <access_token>' \
-H 'X-MeetingIM-APIKey: <api_key>' \
-H 'X-IM-Schema: 1' \
-H 'X-Tenant-Code: default' \
-H 'X-Request-ID: <uuid>' \
-H 'Idempotency-Key: <uuid>' \
--data '{"password":"6439","purpose":"youth_mode","action":"close_youth_mode"}'
```
```bash
curl -sS 'https://api.118im.com/v1/im/settings/youth-mode/disable' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <access_token>' \
-H 'X-MeetingIM-Auth: Bearer <access_token>' \
-H 'X-MeetingIM-APIKey: <api_key>' \
-H 'X-IM-Schema: 1' \
-H 'X-Tenant-Code: default' \
-H 'X-Request-ID: <uuid>' \
-H 'Idempotency-Key: <uuid>' \
-H 'X-Action-Token: <close_token>' \
--data '{}'
```