# IM 阿里云实名认证接入方案 ## 1. 目标 本文记录当前 IM 实名认证能力的实现情况,以及后续接入阿里云实名认证的后端、前端和数据模型改造方案。接入目标是:用户在客户端提交实名信息后,由 IM Server 统一调用阿里云完成身份核验,客户端只感知认证状态和必要的认证跳转参数,不接触阿里云密钥、AccessKey、服务端回调密钥等敏感配置。 阿里云侧建议优先使用金融级实人认证/ID Verification(Cloudauth)能力。产品选型分两类: 1. **姓名 + 身份证二要素核验**:体验最轻,适合只要求姓名和证件号一致性的场景。结果可同步或准同步返回。 2. **增强版实人认证/活体核身**:服务端发起认证并获取 `CertifyId`,客户端通过阿里云 SDK、H5 或认证 URL 完成活体流程,服务端再查询结果或接收回调。适合强实名、风控和合规要求更高的场景。 当前产品原型只有姓名和证件号码输入页,但考虑后续安全要求,后端状态机需要兼容增强版实人认证。 ## 2. 当前已有实现 ### 2.1 前端对接接口 现有前后端文档已定义实名认证页面的三个核心入口: | 能力 | 接口 | 当前状态 | | --- | --- | --- | | 查询实名状态 | `GET /v1/im/security/realname` | 已实现 | | 提交实名信息 | `POST /v1/im/security/realname/submissions` | 已实现 | | 实名更正申诉 | `POST /v1/im/security/realname/appeals` | 已实现 | 查询接口返回: ```json { "status": "unverified", "can_submit": true } ``` 已提交或已通过时返回 `submission_id`、`masked_name`、`masked_id_number`、`verified_at`、`review_reason` 等字段。 提交接口要求: - 必须携带 `Authorization: Bearer `。 - 必须携带 `Idempotency-Key`,服务端根据用户、租户和幂等键生成 `submission_id`。 - Body 目前为: ```json { "name": "张三", "id_type": "cn_id", "id_number": "110101199001011234" } ``` 校验规则: - `name` 长度 2-32 个字符。 - `id_type` 当前只支持 `cn_id`。 - `id_number` 当前只支持 18 位中国大陆身份证号,末位允许 `X`。 ### 2.2 服务端实现 当前代码主要在以下位置: | 模块 | 文件 | 说明 | | --- | --- | --- | | HTTP 路由 | `server/main.go` | 注册 `/v1/im/security/realname`、`/realname/submissions`、`/realname/appeals` | | HTTP Handler | `server/im_http.go` | 查询、提交、申诉逻辑 | | Store 接口 | `server/store/store.go` | `GetRealName`、`CreateRealNameSubmission`、`CreateRealNameAppeal` | | MySQL 实现 | `server/db/mysql/tenant_adapter.go` | 租户库读写实名表 | | 类型定义 | `server/store/types/security.go` | `RealNameVerification`、`RealNameAppeal` | | 内部后台查询 | `server/internal_admin_query_resources.go` | `realname-verifications` 查询资源 | 当前实名提交成功后只落库为 `pending`,不会调用第三方,也没有自动审核通过。重复提交时,如果最新状态是 `pending` 或 `verified`,服务端会直接返回当前状态,避免重复创建申请。 ### 2.3 当前数据表 租户库已有 `im_realname_verifications`: | 字段 | 说明 | | --- | --- | | `id` | 自增主键 | | `user_id` | 用户 ID | | `submission_id` | 实名提交 ID,幂等唯一 | | `status` | 当前状态,已有逻辑使用 `pending`、`verified`、`rejected`、`unverified` | | `name_cipher` | 姓名保护存储值 | | `id_type` | 证件类型 | | `id_number_cipher` | 证件号保护存储值 | | `id_number_hash` | 证件号哈希,用于重复身份检测 | | `masked_name` | 脱敏姓名 | | `masked_id_number` | 脱敏证件号 | | `review_reason` | 审核原因或驳回原因 | | `verified_at` | 通过时间 | | `created_at` / `updated_at` | 创建和更新时间 | 租户库已有 `im_realname_appeals`: | 字段 | 说明 | | --- | --- | | `id` | 雪花 ID | | `appeal_id` | 申诉 ID | | `user_id` | 用户 ID | | `reason` | 申诉原因 | | `attachments_json` | 附件列表 | | `status` | 申诉状态,默认 `pending` | | `review_comment` | 审核备注 | | `created_at` / `updated_at` | 创建和更新时间 | ### 2.4 已记录的增强项 `docs/IM-未实现后续增强项.md` 和 `docs/IM-需求实现情况审核报告.md` 已明确:实名状态查询、提交、申诉已经具备,但缺少后台审核流转、第三方认证结果回写、审核结果通知和完整申诉处理工单。 当前缺口如下: | 缺口 | 影响 | | --- | --- | | 未接第三方实名供应商 | 提交后长期停留 `pending`,无法自动通过或拒绝 | | 缺少 provider 字段 | 无法区分人工审核、阿里云二要素、阿里云活体等来源 | | 缺少第三方任务 ID | 无法通过 `CertifyId` 或外部 request id 查询认证结果 | | 缺少回调/查询状态机 | 无法安全处理异步认证完成、重试和重复通知 | | 缺少后台审核动作 | 人工通过、拒绝、申诉处理还没有完整闭环 | | 缺少结果通知 | 实名通过或拒绝后,还没有统一系统通知事件 | ## 3. 阿里云接入总体方案 ### 3.0 当前联调结论 2026-09-20 已按 `docs/third/三方服务依赖信息.md` 中的阿里云 AccessKey 做过真实接口联调: | 账号 | 调用接口 | 结果 | 结论 | | --- | --- | --- | --- | | 子账号 `t1@1624085816137202.onaliyun.com` | `Id2MetaVerify` | `403 Forbidden.NoPermission`,缺少 `yundun-cloudauth:Id2MetaVerify` | 子账号需要 RAM 授权 | | 主账号 AccessKey | `Id2MetaVerify` | 业务码 `410`,提示“未开通服务” | 当前阿里云账号尚未开通身份证二要素/ID_2META 服务 | 因此代码已接入真实阿里云 API,但生产可用还需要: 1. 在阿里云开通实人认证服务中的身份证二要素核验 `ID_2META`。 2. 给运行时使用的 RAM 子账号授权 `yundun-cloudauth:Id2MetaVerify`,或授予对应实人认证服务策略。 3. 在 `hotgo.hg_sys_config` 的 `im_realname` 分组写入 `realname_provider=aliyun_cloudauth`、`aliyun_access_key_id`、`aliyun_access_key_secret`、`aliyun_region_id`、`aliyun_endpoint`。 4. 租户 `hotgo.im_tenant_config.realname_review_policy=1` 后,IM Server 才会自动调用阿里云;服务未开通、权限不足或返回不一致时都会进入 `manual_review`。 ### 3.1 配置来源 实名认证配置分两层: 1. **全局供应商配置**:阿里云 AccessKey、Endpoint、回调密钥等服务商级参数放在 HotGo 控制库 `hotgo.hg_sys_config`,使用独立分组 `im_realname`。 2. **租户审核策略**:审核方式放在 HotGo 控制库的 `im_tenant_config`。该策略每个租户单独控制,默认 `0=不审核`。 全局供应商配置: | group | key | 建议值 | 说明 | | --- | --- | --- | --- | | `im_realname` | `realname_provider` | `aliyun_cloudauth` | 当前供应商 | | `im_realname` | `aliyun_region_id` | `cn-hangzhou` | 阿里云地域 | | `im_realname` | `aliyun_endpoint` | `cloudauth.aliyuncs.com` | OpenAPI Endpoint,按实际产品确认 | | `im_realname` | `aliyun_access_key_id` | 空 | RAM AccessKey ID,禁止下发客户端 | | `im_realname` | `aliyun_access_key_secret` | 空 | RAM AccessKey Secret,后台脱敏展示 | | `im_realname` | `aliyun_scene_id` | 空 | 实人认证场景 ID,控制台创建 | | `im_realname` | `aliyun_product_code` | 空 | 如产品要求传 product code,则配置 | | `im_realname` | `callback_secret` | 空 | IM Server 校验阿里云回调的本地密钥 | | `im_realname` | `result_query_interval_seconds` | `10` | 异步查询间隔 | | `im_realname` | `result_query_max_attempts` | `30` | 最大查询次数 | | `im_realname` | `mock_enabled` | `0` | 本地/测试环境 mock 开关 | AccessKey 建议使用最小权限 RAM 子账号,只授权实人认证相关 OpenAPI。生产环境如果后续接入 KMS/Secrets Manager,`hg_sys_config` 中可只保存密钥引用。 租户审核策略建议扩展 `hotgo.im_tenant_config`: | 字段 | 默认值 | 说明 | | --- | --- | --- | | `realname_review_policy` | `0` | 审核方式:`0=不审核`,`1=自动审核;自动审核失败/异常/不确定时进入人工审核` | | `realname_provider_mode` | `id_card_2factor` | 第三方核验模式:`id_card_2factor` 或 `smart_verify` | | `realname_required` | `0` | 是否强制实名,影响 `bootstrap.security.realname.required` 和受限写操作 | | `realname_allow_skip` | `1` | 未实名提醒是否允许跳过 | | `realname_remind_after` | `24h` | 客户端实名提醒间隔 | 执行规则: - 租户 `realname_review_policy=0` 时,不做第三方审核,提交实名后写入 `pending`,等待后台人工通过或拒绝。 - 租户 `realname_review_policy=1` 时,IM Server 自动调用阿里云;通过则写 `verified`,失败、异常或结果不确定则写 `manual_review`,等待后台人工复核。 - 阿里云全局配置缺失时,即使租户开启自动审核,也不得阻断系统启动;提交时返回稳定错误,或降级写入 `manual_review` 交给人工审核。 ### 3.2 推荐状态机 本地实名状态建议统一为: | 状态 | 含义 | 前端展示 | | --- | --- | --- | | `unverified` | 未提交或无有效记录 | 可提交 | | `pending` | 已创建本地申请,等待第三方或人工结果 | 审核中 | | `processing` | 第三方认证流程已开始,等待客户端完成或服务端查询 | 认证中 | | `verified` | 第三方或人工审核通过 | 已实名 | | `rejected` | 第三方或人工审核拒绝 | 未通过,可重新提交或申诉 | | `manual_review` | 第三方结果不确定,需要后台人工处理 | 审核中 | | `expired` | 客户端未在有效期完成认证 | 可重新提交 | | `failed` | 第三方调用失败或系统异常 | 可重试 | 对外接口可以继续兼容现有 `unverified|pending|verified|rejected`,把 `processing/manual_review` 展示为 `pending`,把 `expired/failed` 视租户策略映射为 `rejected` 或允许重新提交。 ## 4. 两种接入流程 ### 4.1 二要素核验流程 适合当前页面只提交姓名和身份证号的产品形态。 1. 客户端调用 `POST /v1/im/security/realname/submissions`,提交姓名、证件类型、证件号。 2. IM Server 完成本地格式校验、幂等校验、重复 pending/verified 校验。 3. IM Server 创建本地 `im_realname_verifications`,状态为 `pending`。 4. 如果租户 `realname_review_policy=0`,流程到此结束,等待后台人工审核。 5. 如果租户 `realname_review_policy=1`,IM Server 调用阿里云二要素核验 API。 6. 阿里云返回一致/不一致/无法验证。 7. IM Server 将本地状态更新为: - 一致:`verified`,写入 `verified_at`。 - 不一致:进入 `manual_review`,由后台人工复核。 - 无法验证或供应商异常:进入 `manual_review`,由后台人工复核。 8. 客户端继续调用 `GET /v1/im/security/realname` 获取最终状态。 9. 如接入系统通知,服务端投递 `security.realname.updated`。 这个模式对前端改动最小,但实名强度只覆盖姓名和证件号一致性。 ### 4.2 增强版实人认证流程 适合要求活体、人脸和证件一致性校验的场景。 1. 客户端调用 `POST /v1/im/security/realname/submissions`,提交姓名、证件类型、证件号,并附带阿里云客户端 SDK 要求的 `meta_info`。 2. IM Server 创建本地申请,状态为 `pending`。 3. IM Server 调用阿里云发起认证接口,例如 `InitSmartVerify` 或当前产品对应的初始化接口。 4. 阿里云返回 `CertifyId`、认证 URL、认证 Token 或 SDK 所需参数。 5. IM Server 保存 `provider_task_id=CertifyId`,并把客户端需要的非敏感参数返回给前端。 6. 客户端调起阿里云 SDK、H5 或认证 URL 完成活体核身。 7. IM Server 通过以下任一方式拿最终结果: - 阿里云回调 IM Server。 - IM Server 定时调用结果查询接口,例如 `DescribeSmartVerify` 或当前产品对应的查询接口。 8. IM Server 根据结果更新本地状态为 `verified`、`rejected`、`manual_review`、`expired` 或 `failed`。 9. 客户端轮询 `GET /v1/im/security/realname` 或接收系统通知刷新页面。 增强版模式下,客户端仍然不需要知道 AccessKey、AccessKeySecret、回调密钥等服务端凭据。客户端只使用后端返回的 `certify_id`、`certify_url`、`token`、`expires_at` 等短期认证参数。 ## 5. 前后端接口建议 ### 5.1 提交实名信息 保持现有接口不变: `POST /v1/im/security/realname/submissions` 二要素模式请求: ```json { "name": "张三", "id_type": "cn_id", "id_number": "110101199001011234" } ``` 增强版模式请求可扩展: ```json { "name": "张三", "id_type": "cn_id", "id_number": "110101199001011234", "meta_info": "{\"zimVer\":\"...\"}", "return_url": "meetingim://realname/callback" } ``` 二要素模式响应: ```json { "submission_id": "rn_xxx", "status": "verified", "can_submit": false } ``` 增强版模式响应: ```json { "submission_id": "rn_xxx", "status": "processing", "provider": "aliyun_cloudauth", "mode": "smart_verify", "certify_id": "xxx", "certify_url": "https://...", "token": "短期认证参数,如产品返回", "expires_at": "2026-09-20T10:00:00Z" } ``` ### 5.2 查询实名状态 继续使用: `GET /v1/im/security/realname` 建议扩展字段: ```json { "status": "pending", "display_status": "pending", "provider": "aliyun_cloudauth", "mode": "smart_verify", "submission_id": "rn_xxx", "masked_name": "张*", "masked_id_number": "110***********1234", "can_submit": false, "review_reason": "", "verified_at": null, "next_action": "wait" } ``` `next_action` 建议值: | 值 | 含义 | | --- | --- | | `submit` | 可提交 | | `continue_provider_verify` | 需要继续完成阿里云认证 | | `wait` | 等待结果 | | `appeal` | 可申诉 | | `none` | 无需操作 | ### 5.3 阿里云回调接口 建议新增: `POST /v1/im/security/realname/providers/aliyun/callback` 要求: - 只接收阿里云回调。 - 校验签名、时间戳、nonce 或本地 `callback_secret`。 - 根据 `CertifyId/provider_task_id` 幂等更新状态。 - 原始 payload 写入事件表,敏感字段脱敏或加密。 这个接口不直接暴露给客户端。 ## 6. 数据库改造建议 ### 6.1 扩展实名主表 建议在 `im_realname_verifications` 增加第三方状态字段: ```sql ALTER TABLE im_realname_verifications ADD COLUMN provider VARCHAR(32) NOT NULL DEFAULT '' AFTER status, ADD COLUMN provider_mode VARCHAR(32) NOT NULL DEFAULT '' AFTER provider, ADD COLUMN provider_scene_id VARCHAR(64) NOT NULL DEFAULT '' AFTER provider_mode, ADD COLUMN provider_task_id VARCHAR(128) NOT NULL DEFAULT '' AFTER provider_scene_id, ADD COLUMN provider_request_id VARCHAR(128) NOT NULL DEFAULT '' AFTER provider_task_id, ADD COLUMN provider_status VARCHAR(32) NOT NULL DEFAULT '' AFTER provider_request_id, ADD COLUMN provider_error_code VARCHAR(64) NOT NULL DEFAULT '' AFTER provider_status, ADD COLUMN provider_error_message VARCHAR(256) NOT NULL DEFAULT '' AFTER provider_error_code, ADD COLUMN provider_result_json JSON NULL AFTER provider_error_message, ADD COLUMN submitted_at DATETIME(3) NULL AFTER provider_result_json, ADD COLUMN callback_at DATETIME(3) NULL AFTER submitted_at, ADD COLUMN expires_at DATETIME(3) NULL AFTER callback_at, ADD COLUMN manual_review_required TINYINT(1) NOT NULL DEFAULT 0 AFTER expires_at, ADD COLUMN version BIGINT NOT NULL DEFAULT 1 AFTER manual_review_required, ADD INDEX idx_im_realname_provider_task (provider, provider_task_id), ADD INDEX idx_im_realname_status_updated (status, updated_at); ``` 注意:当前项目已经改为“一个租户一个库”,租户业务表中不再新增 `tenant_id` 字段。 ### 6.2 新增第三方事件表 建议新增 `im_realname_provider_events`,用于记录回调、查询结果和异常响应,便于排查和审计: ```sql CREATE TABLE IF NOT EXISTS im_realname_provider_events ( id BIGINT NOT NULL AUTO_INCREMENT, submission_id VARCHAR(64) NOT NULL, user_id BIGINT NOT NULL, provider VARCHAR(32) NOT NULL, provider_task_id VARCHAR(128) NOT NULL DEFAULT '', event_type VARCHAR(32) NOT NULL, provider_status VARCHAR(32) NOT NULL DEFAULT '', request_id VARCHAR(128) NOT NULL DEFAULT '', signature_valid TINYINT(1) NOT NULL DEFAULT 0, payload_json JSON NULL, error_code VARCHAR(64) NOT NULL DEFAULT '', error_message VARCHAR(256) NOT NULL DEFAULT '', created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), PRIMARY KEY (id), INDEX idx_im_realname_events_submission (submission_id, created_at), INDEX idx_im_realname_events_provider_task (provider, provider_task_id, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; ``` ### 6.3 配置 SQL 建议 HotGo 控制库增加全局供应商配置项: ```sql INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '实名认证 Provider', 'string', 'realname_provider', 'aliyun_cloudauth', 'aliyun_cloudauth', 11, '当前实名认证供应商', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='realname_provider'); INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '阿里云 RegionId', 'string', 'aliyun_region_id', 'cn-hangzhou', 'cn-hangzhou', 20, '阿里云实人认证地域', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='aliyun_region_id'); INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '阿里云 Endpoint', 'string', 'aliyun_endpoint', 'cloudauth.aliyuncs.com', 'cloudauth.aliyuncs.com', 21, '阿里云实人认证 OpenAPI Endpoint,按开通产品确认', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='aliyun_endpoint'); INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '阿里云 AccessKey ID', 'string', 'aliyun_access_key_id', '', '', 22, '敏感配置,禁止下发客户端', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='aliyun_access_key_id'); INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '阿里云 AccessKey Secret', 'string', 'aliyun_access_key_secret', '', '', 23, '敏感配置,后台脱敏展示,禁止下发客户端', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='aliyun_access_key_secret'); INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '阿里云认证场景 ID', 'string', 'aliyun_scene_id', '', '', 24, '增强版实人认证场景 ID', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='aliyun_scene_id'); INSERT INTO hg_sys_config (`group`, `name`, `type`, `key`, `value`, `default_value`, `sort`, `remark`, `status`, `created_by`, `created_at`, `updated_at`) SELECT 'im_realname', '实名认证回调密钥', 'string', 'callback_secret', '', '', 30, 'IM Server 校验回调使用,禁止下发客户端', 1, 1, NOW(), NOW() WHERE NOT EXISTS (SELECT 1 FROM hg_sys_config WHERE `group`='im_realname' AND `key`='callback_secret'); ``` HotGo 控制库增加租户级审核策略。以下写法用于现有库变更,正式发布时可合并到 `im_tenant_config` 建表 SQL: ```sql ALTER TABLE hotgo.im_tenant_config ADD COLUMN realname_review_policy TINYINT(1) NOT NULL DEFAULT 0 COMMENT '实名审核策略:0不审核,1自动审核且失败转人工' AFTER max_group_members, ADD COLUMN realname_provider_mode VARCHAR(32) NOT NULL DEFAULT 'id_card_2factor' COMMENT 'id_card_2factor 或 smart_verify' AFTER realname_review_policy, ADD COLUMN realname_required TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否强制实名' AFTER realname_provider_mode, ADD COLUMN realname_allow_skip TINYINT(1) NOT NULL DEFAULT 1 COMMENT '未实名提醒是否允许跳过' AFTER realname_required, ADD COLUMN realname_remind_after VARCHAR(32) NOT NULL DEFAULT '24h' COMMENT '实名提醒间隔' AFTER realname_allow_skip; ``` 默认值要求: - `realname_review_policy=0`,新租户默认不调用阿里云,也不自动通过;提交后进入 `pending`,等待后台人工审核。 - `realname_review_policy=1`,自动调用阿里云;通过写 `verified`,失败、异常、不确定全部进入 `manual_review`。 - 审核策略只影响当前租户,不影响其他租户。 ## 7. 后端开发拆分 ### 7.1 第一阶段:配置和状态机 1. 新增 `server/realname` 或 `server/identity` 包,封装实名服务。 2. 从 HotGo `hg_sys_config` 读取 `im_realname` 分组供应商配置,并从 `im_tenant_config` 读取当前租户的审核策略。 3. 扩展 `RealNameVerification` 类型和 MySQL adapter 字段。 4. 新增状态更新方法,例如 `TenantRealNameUpdateProviderResult`。 5. 新增 provider 事件表写入方法。 6. 保持现有接口兼容,未配置第三方时仍可创建 `pending` 申请,不影响系统启动。 ### 7.2 第二阶段:阿里云 Client 1. 封装 `AliyunRealNameClient`,支持 mock client 和真实 client。 2. 二要素模式实现:提交姓名、证件号,返回通过/拒绝/人工审核。 3. 增强版模式实现: - 发起认证:调用 `InitSmartVerify`、`InitFaceVerify` 或开通产品对应的初始化 API。 - 查询结果:调用 `DescribeSmartVerify`、`DescribeFaceVerify` 或开通产品对应的查询 API。 4. 记录阿里云 `RequestId`、`CertifyId`、错误码和错误消息。 ### 7.3 第三阶段:回调和异步查询 1. 新增阿里云回调 Handler。 2. 校验回调签名和时间窗口。 3. 以 `provider_task_id` 幂等更新实名状态。 4. 对没有回调或回调失败的任务,后台 worker 定时查询结果。 5. 查询超过最大次数后进入 `manual_review` 或 `failed`。 ### 7.4 第四阶段:后台审核和通知 1. 完善后台审核接口:通过、拒绝、申诉处理、审核备注。 2. 实名通过/拒绝后发送系统通知。 3. `GET /v1/im/bootstrap` 和 `GET /v1/im/me` 统一读取真实实名状态。 4. 接入审计日志,记录管理员和第三方状态变更。 ## 8. 安全与合规要求 1. 客户端不接触阿里云 AccessKey、AccessKeySecret、回调密钥。 2. IM Server 普通日志不得打印姓名、身份证号、阿里云完整返回 payload。 3. 身份证号只保存哈希、脱敏值和必要保护存储值;如必须保存原文,应使用 KMS 或应用层加密,并设置严格读取权限。 4. `provider_result_json` 和事件表 payload 需要脱敏或加密,禁止存储身份证原文、人脸图片、活体照片。 5. 回调接口必须校验签名、时间戳和幂等,避免伪造通过。 6. AccessKey 使用最小权限 RAM 子账号,建议按环境隔离。 7. 后台查询接口需要按 `security_auditor` 等角色授权,敏感字段默认脱敏。 8. 实名通过后的状态变更需要写审计日志,便于追踪。 ## 9. 异常处理策略 | 场景 | 建议处理 | | --- | --- | | 阿里云配置缺失 | 接口返回稳定错误 `REALNAME_PROVIDER_NOT_CONFIGURED`,或按配置退回人工 `pending` | | 阿里云超时 | 本地状态保持 `pending/processing`,后台 worker 重试 | | 阿里云明确不一致 | 状态改为 `rejected`,返回脱敏驳回原因 | | 阿里云结果不确定 | 状态改为 `manual_review` | | 用户重复提交 | 如果已有 `pending/processing/verified`,直接返回最新申请 | | 用户认证中断 | 到期后改为 `expired`,允许重新提交 | | 回调重复到达 | 根据 `provider_task_id + provider_status` 幂等忽略 | ## 10. 客户端改动点 1. 继续使用当前实名提交和查询接口。 2. 如果提交响应包含 `certify_url` 或 `token`,客户端调起阿里云 SDK/H5 认证流程。 3. 认证完成后回到 IM 页面,调用 `GET /v1/im/security/realname` 刷新状态。 4. 客户端不缓存原始姓名和证件号,只展示后端返回的脱敏值。 5. 对 `processing/pending/manual_review` 统一展示“审核中/认证中”。 6. 对 `rejected/expired/failed` 根据 `can_submit` 和 `next_action` 决定是否允许重新提交或申诉。 ## 11. 建议验收点 1. 未配置阿里云时,IM Server 能正常启动,现有实名提交仍可落 `pending`。 2. 配置 mock provider 后,提交实名可以覆盖通过、拒绝、异常和超时场景。 3. 二要素模式下,提交后能自动更新为 `verified/rejected`。 4. 增强版模式下,提交后返回 `certify_id/certify_url`,完成认证后状态能回写。 5. 重复 `Idempotency-Key` 不产生重复申请。 6. 阿里云回调重复投递不重复更新、不重复通知。 7. 日志、系统通知、Push、搜索索引中均不出现身份证原文。 8. 后台能按状态查看实名申请,并能人工处理 `manual_review` 和申诉。 ## 12. 参考文档 - 阿里云 OpenAPI 开发者门户:`https://api.aliyun.com/` - 阿里云实人认证服务 API:`https://api.aliyun.com/product/Cloudauth` - `InitSmartVerify`:发起增强版认证请求,返回认证请求 ID。 - `DescribeSmartVerify`:查询增强版认证结果。 - `InitFaceVerify` / `DescribeFaceVerify`:按开通产品和接入形态选择的实人认证初始化与结果查询接口。 最终使用哪个 API 名称和参数,以实际开通的阿里云产品、地域、控制台场景配置和 API 门户为准。