第2章:国密接口API设计 — RESTful 规范与接口定义

这一章,咱们直接切入正题。

API 设计好不好,直接影响后续的 CI/CD 集成效率。我个人习惯是,在写第一行代码之前,先把接口契约定死。你想想看,如果接口文档和代码对不上,自动化测试跑起来全是误报,CI 流水线再漂亮也没用。

2.1 RESTful 接口规范 — 我们到底在谈什么?

RESTful 不是银弹,但它是目前 CI/CD 工具链支持最好的风格。为什么?因为它的资源路径、HTTP 方法和状态码都是标准化的,Jenkins、GitLab CI 的 HTTP 插件可以直接消费。

咱们直接看几个要点:

  • 资源路径用名词复数:比如 /api/v1/certificates,而不是 /api/v1/getCert。动词交给 HTTP 方法。
  • 版本号放在路径:/api/v1/。我建议直接嵌在 URL 里,别用请求头,CI 脚本解析起来最省事。
  • 查询用 Query 参数:分页、过滤都走 ?page=1&size=20&algorithm=SM2。
  • 请求体用 JSON:不用 XML,不用 Form Data。CI 流水线里拼接 JSON 最可控。
核心原则: 接口契约一旦发布,就不要轻易改路径和字段名。CI/CD 流水线里改一处接口,意味着要同步改测试用例、Mock 服务、部署脚本,非常痛苦。我在项目中吃过这个亏,后来就学乖了。

2.2 国密接口定义 — 加密、签名与验签

国密接口主要分三类:加密解密、签名生成、签名验证。咱们一个一个看。

2.2.1 加密接口

加密接口负责把明文变成密文。这里要注意,国密算法(SM2/SM4)对输入格式有严格要求。我见过不少团队直接把原始二进制塞进去,结果签名验证总是失败。

经验之谈: 统一用 Base64 编码传输。明文和密文都用 Base64 字符串表示,CI 脚本里不用处理字节对齐问题。
POST /api/v1/encrypt
Content-Type: application/json

{
  "algorithm": "SM4",      
  "keyId": "key-sm4-001",  
  "plaintext": "aGVsbG8g5Zu+54mH",  // Base64编码后的明文
  "mode": "CBC",            
  "iv": "MTIzNDU2Nzg5MDEyMzQ1Ng=="  // 初始向量,Base64
}

// 响应示例
{
  "code": 0,
  "message": "success",
  "data": {
    "ciphertext": "5L2g5aW95L2g5a2X56ym",  // Base64编码后的密文
    "keyId": "key-sm4-001"
  }
}

参数说明:

字段 说明 备注
algorithm 算法名称 SM2 / SM4
keyId 密钥标识 CI 流水线通过变量注入
plaintext 明文(Base64) 禁止传原始二进制
mode 加密模式 ECB / CBC / GCM
iv 初始向量 CBC/GCM 模式必传

2.2.2 签名接口

签名接口生成一段数据的数字签名。SM2 签名算法是非对称的,私钥签名,公钥验签。在 CI/CD 场景里,签名用于保证构建产物没有被篡改。

POST /api/v1/sign
Content-Type: application/json

{
  "algorithm": "SM2",      
  "keyId": "key-sm2-sign-001",
  "data": "Y29udGVudCBoYXNo",  // 待签名内容的哈希值(Base64)
  "userId": "ci-builder-01"    // 用户标识,用于派生SM2签名参数
}

// 响应示例
{
  "code": 0,
  "message": "success",
  "data": {
    "signature": "MEUCIQCT...",  // Base64编码的签名值
    "keyId": "key-sm2-sign-001"
  }
}
注意: 签名接口的 data 字段传的是哈希值,不是原始内容。我曾经遇到一个团队直接把整个 APK 传进来,导致超时。正确的做法是:CI 流水线先计算 SHA-256,再把哈希传给签名服务。

2.2.3 验签接口

验签接口验证签名是否合法。它和签名接口是对称的,输入几乎一样,只是多了 signature 字段。

POST /api/v1/verify
Content-Type: application/json

{
  "algorithm": "SM2",
  "keyId": "key-sm2-sign-001",
  "data": "Y29udGVudCBoYXNo",  
  "signature": "MEUCIQCT...",     
  "userId": "ci-builder-01"
}

// 响应示例
{
  "code": 0,
  "message": "success",
  "data": {
    "valid": true,             // true 表示签名验证通过
    "keyId": "key-sm2-sign-001"
  }
}

三个接口的路径和用途很清晰。但要注意错误码要统一。我建议这样设计:

Code 说明 CI/CD 处理建议
0 成功 继续流水线
40001 请求参数非法 打印日志,终止流水线
40002 密钥不存在 检查密钥管理服务连接
40003 签名验证失败 标记构建产物为不可信
50001 内部服务错误 重试 3 次后报错

2.3 接口设计中的避坑指南

接口设计看似简单,但坑不少。我踩过的几个,你们绕开走:

  • 别把密钥 ID 写死在请求体。CI 脚本里用变量 ${KEY_ID} 引用,换环境只需改一行。
  • 签名和验签的 data 必须一致。注意编码,UTF-8 还是 ASCII?统一用 UTF-8 加 Base64,别含糊。
  • 加密模式的 iv 和 key 不能混用。CBC 模式每次加密要生成新 iv,SM4 和 SM2 的 key 长度不同,接口里要分开校验。
  • 超时时间要设长一点。国密算法计算密集,签名可能超过 1 秒。我建议 CI 脚本里设 10 秒超时,避免误报。

2.4 本章知识结构

下面这张图概括了本章的核心内容,从 RESTful 规范到三个国密接口的交互流程,以及 CI/CD 环节的注意事项。

国密接口 API 设计 · 核心结构 RESTful 规范 加密接口 /encrypt 签名接口 /sign 验签接口 /verify 加密接口重点 • algorithm: SM2/SM4 • 明文密文用 Base64 • mode + iv 不可缺失 签名接口重点 • data 传哈希值(Base64) • SM2 需要 userId • CI 里先哈希再签名 验签接口重点 • 输入和签名接口一致 • 响应含 valid 布尔值 • 失败打印日志并终止 CI/CD 关键集成点 密钥变量注入 → 请求 Base64 编码 → 错误码映射
一点建议: 你可以在 Postman 或者 VS Code 的 REST Client 插件里先跑通这三个接口,把示例请求保存下来。CI 脚本里直接复用这些请求,省去重复调试的时间。我个人习惯是把每个接口的请求体模板放在 Git 仓库的 api-specs/ 目录下,随代码一起版本控制。