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

9.3 KiB
Raw Blame History

IM 青少年模式前后端对接文档

1. 基本约定

青少年模式相关接口均为登录后接口。客户端需要携带用户登录 token、普通 API Key 和协议版本头。

公共 Header:

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

所有写接口还需要携带:

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 查询当前状态

GET /v1/im/settings/youth-mode

成功响应:

{
  "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 发起短信身份验证

POST /v1/im/security/challenges

请求体:

{
  "scene": "set_independent_password",
  "channel": "sms"
}

成功响应:

{
  "code": 0,
  "data": {
    "challenge_id": "sec_chg_1",
    "phone_mask": "+861****000",
    "expires_in_seconds": 300,
    "resend_after_seconds": 60
  }
}

手机号由服务端从当前登录用户读取,客户端不提交目标手机号。

2.3 校验短信验证码

POST /v1/im/security/challenges/{challenge_id}/verify

请求体:

{
  "code": "123456"
}

成功响应:

{
  "code": 0,
  "data": {
    "action": "set_independent_password",
    "action_token": "set_password_token",
    "expires_at": "2026-08-20T09:05:00Z"
  }
}

这里拿到的 action_token 只用于设置独立密码,不能直接用于开启青少年模式。

2.4 设置独立密码

POST /v1/im/settings/independent-password

请求体:

{
  "password": "6439",
  "purpose": "youth_mode",
  "action_token": "set_password_token"
}

成功响应:

{
  "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 开启青少年模式

POST /v1/im/settings/youth-mode/enable

请求体:

{
  "policy_version": 1,
  "action_token": "enable_token"
}

成功响应:

{
  "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 校验独立密码

POST /v1/im/settings/independent-password/verify

请求体:

{
  "password": "6439",
  "purpose": "youth_mode",
  "action": "close_youth_mode"
}

成功响应:

{
  "code": 0,
  "data": {
    "action": "close_youth_mode",
    "action_token": "close_token",
    "expires_at": "2026-08-20T09:05:00Z"
  }
}

3.2 关闭模式

POST /v1/im/settings/youth-mode/disable
X-Action-Token: close_token

请求体:

{}

成功响应:

{
  "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 示例

开启流程:

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"}'
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"}'
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>"}'
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>"}'

关闭流程:

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"}'
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 '{}'