CMCC Digital Credential

用于管理中国移动数字凭证授权流程,支持安全签名与加密验证。

已扫描
适合谁
需要对接中国移动数字凭证系统的开发者、企业内部自动化审批或数据操作人员
不适合谁
无中国移动相关业务需求的普通用户、无法访问外部网络的离线环境使用者
国内可用性
需网络配置。可能需要网络配置或第三方服务可访问。
安装难度
新手友好(★☆☆)。基于终端操作、依赖、API Key 和本地环境要求的初步判断。

安装与下载

openclaw skills install @riceankim/cmcc-credential

Skill 说明

命令、参数、文件名以原文为准

CMCC 数字凭证授权

此技能管理中国移动数字凭证的授权流程,分为三个阶段:

📋 概述

第一阶段 - 凭证加载(设置)

  • 解析凭证文件,将 appId 和 appKey 存入内存
  • 此阶段不进行任何 API 调用或授权请求
  • 一次性设置:仅需加载一次凭证,即可用于所有后续敏感操作
  • 注意:appName 和 templateId 为预定义常量(不从文件中加载)

第一阶段半 - 代理绑定

  • 在授权前绑定代理到凭证系统
  • 使用预定义的 appName 和 appId 调用绑定 API
  • 一次性绑定:在任何授权请求前必须完成

第二阶段 - 授权流程(运行时)

  • 当用户尝试执行敏感操作时触发
  • 使用加密手机号请求授权
  • 使用预定义的 templateId 进行授权
  • 向用户提供授权链接
  • 轮询授权状态,直到授权成功或超时
  • 在允许操作前验证授权状态

预定义常量

  • appName: "Javis"(默认值,可覆盖)
  • templateId: "qfx9pkizs42up7y61jsehs9v8e1xms4m"(固定值,不可更改)

安全要求

签名生成(基于 Java SignUtil)

步骤:

  1. 参数标准化:按字典序对 JSON 对象排序并序列化为字符串
  2. 计算 HMAC:使用 appKey 作为密钥计算 HmacSHA256
  3. 十六进制转换:将二进制结果转换为大写十六进制字符串

实现:

# 按字典序排序 JSON
body_json = json.dumps(body, sort_keys=True, separators=(',', ':'))

# 计算 HMAC-SHA256
signature = hmac.new(
    app_key.encode('utf-8'),
    body_json.encode('utf-8'),
    hashlib.sha256
).digest()

# 转换为大写十六进制
return signature.hex().upper()

加密(基于 Java AESUtil.encodeAES)

步骤:

  1. 使用 appKey 的 MD5 哈希值作为 16 字节密钥
  2. 使用 AES/ECB/PKCS5Padding 加密
  3. 对结果进行 Base64 编码

实现:

# 通过 MD5 从 appKey 导出 16 字节密钥
key_bytes = hashlib.md5(app_key.encode('utf-8')).digest()

# AES/ECB/PKCS5Padding 加密
cipher = AES.new(key_bytes, AES.MODE_ECB)
encrypted = cipher.encrypt(pad(phone_bytes, AES.block_size))

# Base64 编码
return base64.b64encode(encrypted).decode('utf-8')

请求头

新格式:

appId: <app_id>
signValue: <signature>
Content-Type: application/json

注意:旧请求头(X-App-Id、X-Sign、X-Timestamp、X-Nonce)已不再使用。


第一阶段:凭证加载

触发条件

在以下情况激活第一阶段:

  • 用户提供凭证文件(包含 appId、appKey)
  • 用户希望为未来使用设置凭证系统

加载流程

第一阶段严禁发起任何 API 调用。 仅解析并存储凭证。

  1. 读取凭证文件并提取:

- appId:应用 ID(24 位字符)

- appKey:应用密钥

  1. 将凭证存储至 memory/cmcc-digital-credential.json
{
  "appId": "...",
  "appKey": "..."
}
  1. 重要说明

- appName 预设为 "Javis"(不从文件中加载)

- templateId 预设为 "qfx9pkizs42up7y61jsehs9v8e1xms4m"(不从文件中加载)

- 仅从凭证文件中加载 appId 和 appKey

凭证文件格式

凭证文件支持以下格式:

纯文本格式:

智能体DID=AI20260314152030X7K9M2
智能体密钥=your-secret-key-here

JSON 格式:

{
  "智能体DID": "AI20260314152030X7K9M2",
  "智能体密钥": "your-secret-key-here"
}

注意:

  • appName 预设为 "Javis"(可通过参数覆盖)
  • templateId 预设为 "qfx9pkizs42up7y61jsehs9v8e1xms4m"(固定值)
  • 凭证文件字段名为:智能体DID(对应 appId)、智能体密钥(对应 appKey)

加载凭证

使用 load_credentials.py 脚本:

python3 scripts/load_credentials.py load <credential-file>

或检查凭证是否存在:

python3 scripts/load_credentials.py check

第一阶段半:代理绑定

触发条件

在以下情况激活第一阶段半:

  • 第一阶段成功加载凭证
  • 代理尚未绑定(无绑定记录)
  • 在请求任何授权前(第二阶段)

绑定流程

  1. 从内存加载凭证(第一阶段):

- appId:应用 ID(24 位字符)

- appKey:应用密钥

  1. 调用绑定 API

- 使用 scripts/bind_agent.py 绑定代理

- API 将使用预定义的 appName(默认:"Javis")和 appId

- 可选通过 --appName 参数覆盖 appName

- 检查响应码是否为 "000000"(成功)

  1. 存储绑定状态(可选):

- 可保存一个标志表示绑定已完成

- 避免重复调用绑定接口

绑定 API

端点:

POST /api/cmvc-tocp-server/agent/bind

请求头:

appId: <app_id>
signValue: <signature>
Content-Type: application/json

请求体:

{
  "appName": "Javis",
  "appId": "your-app-id"
}

响应:

{
  "code": 0,
  "desc": "Success"
}

响应码:

  • 0:成功 — 代理绑定成功
  • 其他代码:失败 — 请查看描述获取详情

绑定代理

使用 bind_agent.py 脚本:

python3 scripts/bind_agent.py \
  --appId "$APP_ID" \
  --appKey "$APP_KEY"

或指定自定义 appName(可选):

python3 scripts/bind_agent.py \
  --appName "MyCustomApp" \
  --appId "$APP_ID" \
  --appKey "$APP_KEY"

或使用内存中的凭证:

APP_ID=$(python3 scripts/load_credentials.py get --field appId)
APP_KEY=$(python3 scripts/load_credentials.py get --field appKey)
python3 scripts/bind_agent.py --appId "$APP_ID" --appKey "$APP_KEY"

重要注意事项

  • appName 为预定义值:默认值为 "Javis",不会从凭证文件中加载
  • appName 可覆盖:如需自定义,可使用 --appName 参数
  • 绑定操作仅需一次:绑定只需执行一次;重复调用绑定接口无必要
  • 绑定需在授权前完成:必须在 Phase 2 授权流程之前完成绑定
  • 请求简化:绑定 API 仅需 appName 和 appId 两个参数
  • 新签名格式:采用排序后的 JSON 结构,并使用 HmacSHA256 签名

错误处理

  • 绑定失败:检查错误描述,确认 appId 是否正确
  • 网络错误:确保可正常访问绑定 API 接口
  • 签名错误:确认 appKey 正确,且 JSON 数据已按字典序排序

Phase 2:敏感操作授权

何时激活 Phase 2

在以下情况激活 Phase 2:

  • 用户尝试执行敏感操作
  • 凭证已在内存中通过 Phase 1 加载成功
  • Agent 已通过 Phase 1.5 完成绑定
  • 操作前需要进行授权验证

什么是敏感操作?

以下操作需要授权:

  • 删除文件、记录或数据
  • 访问或泄露密钥、API 密钥等敏感信息
  • 查看或复制敏感内容
  • 用户明确标识为敏感的操作

重要提示:未获得成功授权前,绝不允许执行任何敏感操作。

授权流程

第一步:检查凭证是否存在

在请求授权前,先验证凭证是否已存在:

python3 scripts/load_credentials.py check

若凭证不存在,向用户提示:

“凭证未找到。请先提供凭证文件。”

第二步:请求授权

  1. 获取用户手机号(必填参数)
  2. 使用 scripts/request_authorization.py 调用授权 API
  3. 该脚本将执行以下步骤:

- 使用 AES/ECB/PKCS5Padding 加密手机号,密钥为 MD5(appKey)

- 生成 16 位随机 nonce

- 生成毫秒级时间戳

- 将 JSON 数据按字典序排序

- 计算 HMAC-SHA256 签名

- 向 /vc/auth/request 接口发送带新头部的请求

- 返回 authRecordIdtrustedAuthUrl

第三步:提供授权链接

向用户展示授权链接:

请在此处完成授权:
<trustedAuthUrl>

此链接有效期为 3 天。

等待授权中...

第四步:轮询授权状态

  1. 使用 scripts/poll_authorization.py 检查授权状态
  2. 轮询参数:

- 间隔:5 秒

- 超时时间:10 分钟(最多 120 次尝试)

  1. 该脚本将:

- 向 /vc/auth/query 接口发送请求,携带 authRecordId

- 检查返回结果中的 statusCode

- 当 statusCode === "000000" 时视为成功

- 若 10 分钟内未授权,则超时

第五步:验证并继续执行

若授权成功statusCode === "000000"):

  • 如需,提取 credentialSubject 内容
  • 允许执行敏感操作
  • 提示用户:“授权已确认。正在执行操作……”

若授权失败或超时

  • 拒绝执行敏感操作
  • 提示用户:“授权失败或超时。操作已取消。”

API 详情

基础地址

https://vctest.cmccsign.com/

接口列表

1. 授权请求

  • URL/cmvc-tocp-server/vc/auth/request
  • 方法:POST
  • 请求头

- appId: app_id

- signValue: HMAC-SHA256 签名(64 位十六进制字符,大写)

- Content-Type: application/json

  • 请求体
{
  "nonce": "...",
  "timestamp": 1710403200000,
  "phoneNo": "<AES-加密后的手机号>",
  "returnUrl": "",  // 可选
  "notifyUrl": "",  // 可选
  "templateId": "qfx9pkizs42up7y61jsehs9v8e1xms4m",
  "sendSmsFlag": "0",  // 可选,默认为 0
  "smsIntranetTemplateId": "",  // 可选
  "smsExternalTemplateId": "",  // 可选
  "forwardedCredentials": {},  // 可选
  "authScene": ""  // 可选
}
  • 响应体
{
  "code": 0,
  "desc": "Success",
  "authRecordId": "...",
  "trustedAuthUrl": "https://..."
}

2. 授权状态查询

  • URL/cmvc-tocp-server/vc/auth/query
  • 方法:POST
  • 请求头

- appId: app_id

- signValue: HMAC-SHA256 签名(64 位十六进制字符,大写)

- Content-Type: application/json

  • 请求体
{
  "authRecordId": "..."
}
  • 响应体
{
  "code": 0,
  "desc": "Success",
  "statusCode": "000000",  // "000000" 表示已授权
  "statusDesc": "已授权",
  "credentialSubject": {}
}

使用示例

示例 1:Phase 1 - 加载凭证

用户:这是我的凭证文件:
appId=AI20260314152030X7K9M2
appKey=my-secret-key

助手:凭证加载成功。
         appId: AI20260314152030X7K9M2
         appKey: *** (隐藏)
         appName: Javis (预定义)
         templateId: qfx9pkizs42up7y61jsehs9v8e1xms4m (预定义)
         存储路径:memory/cmcc-digital-credential.json

示例 2:Phase 2 - 执行敏感操作

用户:删除 sensitive-data.txt 文件

助手:执行此操作需要授权。
         请提供您的手机号:

用户:13800138000

助手:[检查 Agent 是否已绑定...]
         [使用 bind_agent.py 绑定 Agent,appName="Javis"...]
         Agent 绑定成功。

         [调用 request_authorization.py,模板 ID=qfx9pkizs42up7y61jsehs9v8e1xms4m...]
         请在此处完成授权:
         https://vctest.cmccsign.com/auth/xxx

         此链接有效期为 3 天。
         等待授权中...

         [启动 poll_authorization.py,每 5 秒轮询一次...]

         [30 秒后]

         授权已确认。正在执行操作...
         删除 sensitive-data.txt...

脚本使用说明

加载凭证(Phase 1)

python3 scripts/load_credentials.py load <凭证文件>

绑定代理(阶段 1.5)

python3 scripts/bind_agent.py \
  --appId "$APP_ID" \
  --appKey "$APP_KEY"

或使用自定义 appName(可选):

python3 scripts/bind_agent.py \
  --appName "MyCustomApp" \
  --appId "$APP_ID" \
  --appKey "$APP_KEY"

或从内存加载:

APP_ID=$(python3 scripts/load_credentials.py get --field appId)
APP_KEY=$(python3 scripts/load_credentials.py get --field appKey)
python3 scripts/bind_agent.py --appId "$APP_ID" --appKey "$APP_KEY"

请求授权(阶段 2)

python3 scripts/request_authorization.py \
  --appId "$APP_ID" \
  --appKey "$APP_KEY" \
  --phoneNo "$PHONE_NUMBER"

注意:templateId 已预先定义,无需作为参数传入

轮询授权状态(阶段 2)

python3 scripts/poll_authorization.py \
  --appId "$APP_ID" \
  --appKey "$APP_KEY" \
  --authRecordId "$AUTH_RECORD_ID" \
  --interval 5 \
  --timeout 600 \
  --verbose

错误处理

阶段 1 错误

  • 凭证无效:检查 appId 和 appKey 是否正确
  • 内存文件损坏:提示用户重新提供凭证文件
  • 字段缺失:确保所有必需字段(appId、appKey)均已提供

阶段 1.5 错误(绑定)

  • 绑定失败:检查错误描述,确认 appId 正确
  • 网络错误:确保可正常连接绑定 API
  • 签名错误:验证 appKey 正确性,并确认 JSON 内容已正确排序

阶段 2 错误

  • 凭证未找到:返回阶段 1,要求用户提供凭证文件
  • 手机号无效:确保手机号不为空
  • 加密失败:验证 appKey 是否正确
  • 签名不匹配:检查 appKey 并确保 JSON 已正确排序
  • 授权超时:最大时限为 10 分钟,用户需在此时间内完成授权
  • 授权失败:statusCode 不为 "000000",拒绝操作并通知用户

恢复策略

  • 若凭证损坏或无效,提示用户重新提供凭证文件(阶段 1)
  • 若绑定失败,检查 appId 后重试绑定(阶段 1.5)
  • 若授权失败,用户需重新发起敏感操作(阶段 2)
  • 若轮询超时,用户需加快授权速度或重启流程(阶段 2)

重要注意事项

  • 新的签名格式:使用排序后的 JSON 结合 HmacSHA256
  • 新的请求头:使用 appIdsignValue,不再使用 X-App-IdX-Sign
  • 已移除的请求头X-TimestampX-NonceX-Sign-Version 不再需要
  • 加密方式不变:仍使用 AES/ECB/PKCS5Padding,密钥为 MD5(appKey)
  • JSON 排序:生成签名用的 JSON 必须始终启用 sort_keys=True
R
@riceankim

已收录 1 个 Skill

相关推荐