第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 环节的注意事项。
一点建议: 你可以在 Postman 或者 VS Code 的 REST Client 插件里先跑通这三个接口,把示例请求保存下来。CI 脚本里直接复用这些请求,省去重复调试的时间。我个人习惯是把每个接口的请求体模板放在 Git 仓库的
api-specs/ 目录下,随代码一起版本控制。