跳转至

OpenAPI 加密鉴权接入指南

本文档面向调用 AnyMetrics OpenAPI 的接入方(客户端),说明如何对请求进行加密鉴权。核心动作只有一个:把你要代表的用户 **userId** 加密成 **token**,随请求头发送

适用对象与前置条件

适用对象:需要调用 AnyMetrics OpenAPI 的系统接入方、后端开发人员、运维或集成实施人员。

接入前请确认:

  • 已获得 AnyMetrics 租户 ID,即请求头 tenant-id 的取值。

  • 已确认要代表哪个 AnyMetrics 用户发起调用,并拿到该用户的 userId

  • 管理员已在管理台开启「OPEN API 鉴权」,并提供 RSA 公钥或 AES 对称密钥。

  • 推荐优先使用 RSA;只有在客户端环境完全可信时才考虑 AES。

1. 总览

AnyMetrics OpenAPI 的加密鉴权流程:

  1. 管理员在 AnyMetrics 管理台「企业安全 → OPEN API 鉴权」开启功能并生成密钥,复制出公钥(RSA)或对称密钥(AES)交给接入方。

  2. 接入方用拿到的密钥,把目标用户的 userId(明文)加密成 token

  3. 调用 OpenAPI 时带上两个请求头:tenant-id 和 token

  4. 服务端用对应私钥/对称密钥解出 userId,以该用户身份执行查询。

1.1 管理员配置入口

管理员进入 AnyMetrics 管理台后,按下图路径打开 OPEN API 鉴权页面:

Clipboard_Screenshot_1781490585.png

图中标注说明:

  • 1:顶部导航进入「管理设置」。

  • 2:左侧菜单进入「企业安全 → OPEN API 鉴权」。

在该页面开启 OPEN API 鉴权后,选择加密方式并生成密钥。使用 RSA 时复制「公钥」给接入方;使用 AES 时复制「对称密钥」给接入方。

支持两种加密方式:

方式 客户端持有 安全性 适用
RSA(推荐) 公钥(只能加密,不能解密) 任意客户端
AES 对称密钥(既能加密也能解密) 较低 仅受信任客户端

⚠️ 优先用 RSA。 AES 是对称密钥,等同于把"主密钥"交给客户端——任何持有者都能冒充该租户下任意用户。只有在客户端环境完全可信时才使用 AES。详见 §6 安全说明


2. token 明文规则

明文 = 你要代表的 AnyMetrics 用户的 **userId** 字符串

  • 不需要 JSON 包装,不需要拼时间戳,就是 userId 本身这一个字符串。

  • 例如明文 "100023",加密后得到一段 Base64,即为 token

  • 每个 userId 加密一次即可复用(token 不含过期时间)。


3. 加密规范(协议契约)

接入方的加密参数必须与服务端完全一致,否则解密失败。以下是系统使用的全部默认值。

3.1 RSA

参数
变换(transformation) RSA/ECB/PKCS1Padding
密钥长度 2048 bit
公钥格式 X.509 / SubjectPublicKeyInfo (SPKI),Base64 编码
加密输入 userId 的 UTF-8 字节
加密输出 密文字节的 Base64 字符串 → 即 token

管理员复制给你的"公钥"就是上面的 Base64 SPKI 字符串,直接用。

3.2 AES

重点:以下默认值中,只有「对称密钥」会从管理台复制给你,其余(IV / 算法 / tagSize)都不会下发,必须由你按下表写死,才能和服务端对上。

参数 来源
算法(transformation) AES/GCM/NoPadding 固定,需写死
密钥长度 256 bit 由密钥本身决定
对称密钥 Base64 编码的 256bit 密钥 管理台复制
IV / Nonce **w7ZdfXjV+o+L**(Base64,解码后 12 字节) 固定,需写死
GCM 认证标签长度(tagSize) 128 bit 固定,需写死
AAD(附加认证数据)
加密输入 userId 的 UTF-8 字节
加密输出 密文 ‖ 16字节GCM认证标签 整体的 Base64 字符串 → 即 token

关于输出格式:AES/GCM/NoPadding 在 Java Cipher.doFinal / Python AESGCM.encrypt 下都会把 16 字节(128bit)认证标签拼在密文末尾,再整体 Base64。两端格式天然一致,无需自己拆/拼标签。

⚠️ IV 固定是有意为之(这样才能不下发、客户端写死对接),代价是同一密钥下 GCM nonce 复用,密码学强度降低。这也是 AES 仅限受信任客户端的原因。


4. 参考代码

下面的代码做的事完全一致:输入 userId 明文 + 管理台给的密钥,输出 token(Base64)

4.1 Java

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class AnyMetricsTokenEncryptor {
    // ---------- RSA(推荐)----------
    // publicKeyBase64:管理台复制的公钥
    public static String encryptByRsa(String userId, String publicKeyBase64) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64);
        PublicKey publicKey = KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(keyBytes));
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encrypted = cipher.doFinal(userId.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    // ---------- AES(仅受信任客户端)----------
    private static final String AES_IV   = "w7ZdfXjV+o+L";   // 固定默认 IV,需写死
    private static final int    TAG_SIZE = 128;              // 固定,需写死
    // keyBase64:管理台复制的对称密钥
    public static String encryptByAes(String userId, String keyBase64) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(Base64.getDecoder().decode(keyBase64), "AES");
        byte[] iv = Base64.getDecoder().decode(AES_IV);
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new GCMParameterSpec(TAG_SIZE, iv));
        byte[] encrypted = cipher.doFinal(userId.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }
    public static void main(String[] args) throws Exception {
        String userId = "100023";
        System.out.println("RSA token: " + encryptByRsa(userId, "<公钥Base64>"));
        System.out.println("AES token: " + encryptByAes(userId, "<对称密钥Base64>"));
    }
}

4.2 Python

依赖:pip install cryptography

import base64
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.serialization import load_der_public_key
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# ---------- RSA(推荐)----------
# public_key_b64:管理台复制的公钥
def encrypt_by_rsa(user_id: str, public_key_b64: str) -> str:
    public_key = load_der_public_key(base64.b64decode(public_key_b64))
    # RSA/ECB/PKCS1Padding == RSA PKCS#1 v1.5
    encrypted = public_key.encrypt(user_id.encode("utf-8"), padding.PKCS1v15())
    return base64.b64encode(encrypted).decode("utf-8")
# ---------- AES(仅受信任客户端)----------
AES_IV = "w7ZdfXjV+o+L"   # 固定默认 IV,需写死
# key_b64:管理台复制的对称密钥;AESGCM 默认 128bit 标签,与 tagSize=128 一致
def encrypt_by_aes(user_id: str, key_b64: str) -> str:
    key = base64.b64decode(key_b64)
    iv = base64.b64decode(AES_IV)
    # encrypt 返回 密文 + 16字节标签,与服务端格式一致
    encrypted = AESGCM(key).encrypt(iv, user_id.encode("utf-8"), None)
    return base64.b64encode(encrypted).decode("utf-8")
if __name__ == "__main__":
    uid = "100023"
    print("RSA token:", encrypt_by_rsa(uid, "<公钥Base64>"))
    print("AES token:", encrypt_by_aes(uid, "<对称密钥Base64>"))

需要其他语言(Node.js / Go / C# 等)的示例可联系我们补充——核心参数与上表一致,照搬即可。


5. 携带 token 发起请求

加密得到 token 后,调用 OpenAPI 时带上请求头:

请求头
tenant-id 你的租户 ID
token 上一步加密得到的 token(Base64)
Content-Type application/json

示例(以指标查询为例):

curl -X POST 'https://<host>/anymetrics/api/v1/metrics/queryMetricResultDetails' \
  -H 'tenant-id: tn_1578931' \
  -H 'token: <加密后的token>' \
  -H 'Content-Type: application/json' \
  -d '{
        "metricCode": "order_count",
        "dimensions": [],
        "filters": []
      }'

请求体(指标编码、维度、过滤条件等)按各 OpenAPI 接口文档填写,本指南只负责鉴权部分。


6. 安全说明

  • 首选 RSA:客户端只持有公钥,只能加密自己的 userId,无法解密或伪造其他内容。

  • AES 是安全降级:对称密钥同时能加密和解密,任何持有者都能冒充该租户下任意用户;且本系统 AES 使用固定 IV(GCM nonce 复用),强度进一步降低。仅在客户端运行环境完全可信时使用

  • 密钥务必通过安全渠道交付与保管,不要硬编码进公开仓库或前端可见代码。

  • 管理员可在管理台重新生成密钥进行轮换;轮换后旧 token 立即失效,需用新密钥重新加密。


7. 常见问题与排查

现象 可能原因
解密失败 / 鉴权不通过 加密参数与 §3 不一致:RSA 变换写成了 RSA/ECB/OAEP...、AES 的 IV/tagSize/算法没按默认值写死、密钥复制有缺漏。
openapi auth key not found 管理员尚未生成密钥,或刚改过密钥格式后未重新生成;让管理员在管理台重新生成。
AES 能加密但服务端解不出 IV 没用固定值 w7ZdfXjV+o+L,或标签长度不是 128bit。
提示用户不存在 明文 userId 不是该租户下的有效用户。

附录:参数速查

RSA AES
变换 RSA/ECB/PKCS1Padding AES/GCM/NoPadding
密钥长度 2048 bit 256 bit
客户端持有 公钥 (X.509 SPKI Base64) 对称密钥 (Base64)
IV 不适用 w7ZdfXjV+o+L(固定,写死)
tagSize 不适用 128 bit(固定,写死)
明文 userId userId
输出 密文 Base64 (密文‖16字节标签) Base64