Skip to content
共绩算力文档中心

Open API RSA 模式使用指南

🥑

本文档旨在详细指导用户如何使用 RSA 模式调用共绩算力 Open API,并提供基于 Python 的实现示例。

在开始之前,请确保您已准备好以下环境和工具:

  • Python 环境(可选):确保您的系统已安装 Python 3.6 或更高版本。
  • 必要的 Python 库(可选):您需要安装 cryptography 库用于 RSA 加签,以及 requests 库用于发送 HTTP 请求。您可以使用 pip 进行安装:pip install cryptography requests
  • OpenSSL 工具:通常用于在本地生成 RSA 密钥对。大多数 Linux/macOS 系统自带,Windows 用户可能需要单独安装。
  • 您的 RSA 密钥文件:您需要一个 RSA 密钥文件(通常是 .key 或 .pem 格式),该密钥是您提供给平台所对应的密钥。

使用 RSA 模式的第一步是生成 RSA 密钥对并在平台设置您的公钥。

  1. 在本地生成 RSA 密钥对:
    • 打开终端或命令行工具(如 PowerShell, CMD, Bash)。
    • 使用 OpenSSL 生成私钥文件(例如 2048 位):openssl genrsa -out private.key 2048
    • 从私钥中提取公钥文件:openssl rsa -pubout -in private.key -out public.pem
    • 执行完成后,您将得到 private.key(私钥,务必妥善保管,切勿泄露)和 public.pem(公钥,用于提供给平台)两个文件。
  1. 在平台设置您的公钥:
    • 登录共绩算力平台。
    • 进入 API 密钥管理页面 https://console.suanli.cn/settings/key
    • 点击“新建密钥”,选择“RSA 加验签模式”。
    • 填写备注并提供您的 RSA 公钥。 使用文本编辑器打开您本地生成的 public.pem 文件,复制从 -----BEGIN PUBLIC KEY----------END PUBLIC KEY----- 的全部内容,粘贴到平台对应的输入框。
    • 系统将生成并展示与您公钥匹配的 RSA 公钥 以及其他相关信息。

重要: 请务必立即妥善保管生成的私钥和相关信息,因为它们只会显示一次。一旦丢失,您将无法找回,只能重新生成新的密钥对。平台仅保存您的公钥用于验证签名。

在平台设置密钥时,可能会涉及不同的密钥格式。理解这些格式有助于您正确处理密钥文件:

  • RsaPkcs8Pem

    • 结构:符合 PKCS#8 标准的 RSA 密钥
    • 格式:PEM 编码(含头部/尾部标签的文本文件,如 -----BEGIN PRIVATE KEY-----)
    • 用途:通用性强,适用于配置文件、文件存储
  • RsaPkcs1Pem

    • 结构:符合 PKCS#1 标准的 RSA 密钥(原始 RSA 参数)
    • 格式:PEM 编码(含 RSA 专属标签,如 -----BEGIN RSA PRIVATE KEY----- )
    • 用途:兼容需要 PKCS#1 格式的旧系统
  • RsaPkcs8Base64

    • 结构:PKCS#8 标准密钥
    • 格式:纯 Base64 字符串(无 PEM 标签)
    • 用途:适合代码嵌入或 API 直接传输
  • 首选 RsaPkcs8Pem:平台通常默认此格式,通用性最佳,便于文件保管和配置。
  • 特殊场景选其他
    • 需对接传统系统 → RsaPkcs1Pem
    • 需密钥值直接嵌入代码 → RsaPkcs8Base64

注:平台在您选择并生成密钥后,密钥内容只会展示一次,请务必及时、妥善保管。

3. 使用 Python 脚本进行加签和调用

Section titled “3. 使用 Python 脚本进行加签和调用”

我们已经为您准备了一个 Python 脚本 rsa_sign_util.py 来帮助您实现加签和 API 调用过程。

"""
共绩算力 Open API RSA 模式调用工具类
本模块提供了一个完整的 RSA 加验签和加密的 API 调用工具类,支持:
1. RSA-SHA256 签名生成
2. RSA 公钥加密请求体
3. 自动化的 HTTP 请求发送
4. 完整的错误处理
主要特性:
- 支持带密码的私钥文件
- 自动分段加密大数据
- 灵活的请求方法支持
- 完整的请求头构建
使用前准备:
1. 安装依赖:pip install cryptography requests
2. 准备 RSA 密钥对文件
3. 获取 API 密钥和平台地址
作者:共绩算力技术团队
版本:1.0.0
"""
import base64
import json
import time
import requests
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
class GjRequest:
"""
共绩算力 Open API RSA 模式请求工具类
该类封装了完整的 RSA 加验签和加密流程,提供简单易用的 API 调用接口。
主要功能:
- 自动读取和管理 RSA 密钥对
- 生成符合平台规范的签名
- 支持请求体加密
- 发送 HTTP 请求并返回响应
使用流程:
1. 实例化类并传入必要参数
2. 调用 request() 方法发送请求
3. 处理返回的响应对象
示例:
gj_request = GjRequest(
base_url="https://openapi.suanli.cn",
api_key="your-api-key",
private_key_path="./private.key",
public_key_path="./public.pem",
private_key_pwd=None
)
response = gj_request.request(
uri="/api/deployment/resource/search",
method="GET"
)
"""
# API 版本号,根据平台要求设置
version = 1
def __init__(
self,
base_url: str,
api_key: str,
private_key_path: str,
public_key_path: str,
private_key_pwd: str | None,
):
"""
初始化 GjRequest 实例
Args:
base_url (str): API 网关基础地址,如 "https://openapi.suanli.cn"
api_key (str): 平台分配的 API 密钥,用于认证和签名
private_key_path (str): RSA 私钥文件路径,用于生成签名
public_key_path (str): RSA 公钥文件路径,用于加密请求体
private_key_pwd (str | None): 私钥文件密码,如果私钥未加密则为 None
Raises:
Exception: 当密钥文件读取失败或格式错误时抛出异常
注意:
- 私钥文件必须妥善保管,切勿泄露
- 公钥文件用于加密,私钥文件用于签名
- 如果私钥有密码保护,请确保传入正确的密码
"""
self.base_url = base_url
# 初始化时读取密钥文件,避免重复读取
self.public_key = self.read_public_key(public_key_path)
self.private_key = self.read_private_key(private_key_path, private_key_pwd)
self.api_key = api_key
@staticmethod
def read_private_key(private_key_path: str, private_key_pwd: bytes | None = None):
"""
读取并解析 RSA 私钥文件
支持多种私钥格式:
- PKCS#1 格式 (-----BEGIN RSA PRIVATE KEY-----)
- PKCS#8 格式 (-----BEGIN PRIVATE KEY-----)
Args:
private_key_path (str): 私钥文件路径
private_key_pwd (bytes | None): 私钥密码,如果私钥未加密则为 None
Returns:
解析后的私钥对象,可直接用于签名操作
Raises:
Exception: 当文件不存在或解析失败时抛出异常
注意事项:
- 确保私钥文件路径正确
- 如果私钥有密码,请传入正确的密码
- 私钥文件应为 PEM 格式
"""
try:
# 读取私钥文件
with open(private_key_path, "rb") as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=private_key_pwd, # 如果私钥有密码,请在此提供
backend=default_backend()
)
except FileNotFoundError:
raise Exception(f"错误:私钥文件未找到:{private_key_path}")
except Exception as e:
raise Exception(f"错误:加载私钥失败:{e}")
return private_key
@staticmethod
def read_public_key(public_key_path: str):
"""
读取并解析 RSA 公钥文件
支持标准 PEM 格式的公钥文件:
- PKCS#1 格式 (-----BEGIN RSA PUBLIC KEY-----)
- PKCS#8 格式 (-----BEGIN PUBLIC KEY-----)
Args:
public_key_path (str): 公钥文件路径
Returns:
解析后的公钥对象,可用于加密操作
Raises:
Exception: 当文件不存在或解析失败时抛出异常
注意事项:
- 确保公钥文件路径正确
- 公钥文件应为 PEM 格式
- 公钥用于加密,私钥用于签名
"""
try:
with open(public_key_path, "rb") as key_file:
# 尝试加载 PEM 格式的公钥
public_key = serialization.load_pem_public_key(
key_file.read(),
backend=default_backend()
)
except FileNotFoundError:
raise Exception(f"错误:公钥文件未找到:{public_key_path}")
except Exception as e:
raise Exception(f"错误:加载公钥失败:{e}")
return public_key
def gen_sign(
self,
uri: str,
version: int,
timestamp: int,
token: int,
body: str
):
"""
生成符合平台规范的 RSA-SHA256 签名
签名算法说明:
1. 构建待签名字符串:uri\nversion\ntimestamp\ntoken\nbody
2. 使用 RSA-SHA256 算法进行签名
3. 对签名结果进行 Base64 编码
签名字符串格式:
- uri: API 接口路径,如 "/api/deployment/resource/search"
- version: API 版本号
- timestamp: 时间戳(毫秒)
- token: API 密钥
- body: 请求体内容,如果为空则为空字符串
Args:
uri (str): API 接口路径,必须以 "/" 开头
version (int): API 版本号
timestamp (int): 时间戳,毫秒级
token (int): API 密钥
body (str): 请求体内容,如果为空则为空字符串
Returns:
str: Base64 编码的签名字符串
注意事项:
- 确保时间戳为毫秒级
- 请求体为空时,body 参数应为空字符串
- 签名使用 PKCS1v15 填充和 SHA256 哈希算法
"""
# 构建待签名字符串,严格按照平台规范
sign_str = f"{uri}\n{version}\n{timestamp}\n{token}\n{body}"
# 使用 RSA 私钥和 SHA-256 算法进行签名
sign_encrypt = self.private_key.sign(
sign_str.encode('utf-8'),
padding.PKCS1v15(), # 填充方式:PKCS1v15
hashes.SHA256() # 哈希算法:SHA-256
)
# 将签名结果进行 Base64 编码
sign_str_base64 = base64.b64encode(sign_encrypt).decode('utf-8')
return sign_str_base64
def encrypt_body(
self,
data: str,
):
"""
使用 RSA 公钥加密请求体数据
加密流程:
1. 将数据转换为 JSON 字符串
2. 将 JSON 字符串转换为字节数组
3. 分段加密(RSA 加密有长度限制)
4. 合并加密结果并进行 Base64 编码
分段加密说明:
- RSA-2048 密钥最大加密长度为 256 字节
- 减去 PKCS1v15 填充后,实际可加密长度为 244 字节
- 超过此长度的数据需要分段加密
Args:
data (str): 待加密的数据,通常为 JSON 字符串
Returns:
str: Base64 编码的加密数据
Raises:
Exception: 当加密失败时抛出异常
注意事项:
- 加密会增加数据长度
- 分段加密会生成多个加密块
- 返回结果为 Base64 编码的字符串
"""
try:
# 将数据转换为紧凑的 JSON 字符串(无空格)
json_str = json.dumps(data, separators=(',', ':'), ensure_ascii=False)
data_bytes = json_str.encode('utf-8')
encrypted_chunks = []
# 分段加密:每次最多加密 244 字节
start = 0
data_len = len(data_bytes)
while start < data_len:
end = min(start + 244, data_len)
chunk = data_bytes[start:end]
# 使用 RSA 公钥加密当前数据块
encrypted_chunk = self.public_key.encrypt(
chunk,
padding.PKCS1v15() # 使用 PKCS1v15 填充
)
encrypted_chunks.append(encrypted_chunk)
start = end
# 合并所有加密块
encrypted_data = b''.join(encrypted_chunks)
# 将加密结果进行 Base64 编码
encrypted_base64 = base64.b64encode(encrypted_data).decode('utf-8')
return encrypted_base64
except Exception as e:
# 记录错误但不暴露敏感信息
raise Exception(f"错误:数据加密失败:{e}")
def request(
self,
uri: str,
is_encrypt: bool = False,
method: str | None = None,
json_data: dict | None = None,
params: dict | None = None
):
"""
发送 HTTP 请求到指定的 API 接口
完整的请求流程:
1. 确定 HTTP 方法(GET/POST)
2. 处理请求体(可选加密)
3. 构建完整 URL
4. 生成时间戳和签名
5. 设置请求头
6. 发送请求并返回响应
方法自动判断逻辑:
- 如果未指定方法且无请求体 → GET 请求
- 如果未指定方法但有请求体 → POST 请求
- 如果明确指定方法 → 使用指定方法
Args:
uri (str): API 接口路径,如 "/api/deployment/resource/search"
is_encrypt (bool): 是否加密请求体,默认 False
method (str | None): HTTP 方法,如 "GET", "POST",默认自动判断
json_data (dict | None): 请求体数据,JSON 格式,默认 None
params (dict | None): URL 查询参数,默认 None
Returns:
requests.Response: HTTP 响应对象
请求头说明:
- Content-Type: application/json
- version: API 版本号
- timestamp: 时间戳(毫秒)
- sign_str: RSA 签名
- token: API 密钥
注意事项:
- 时间戳自动生成,确保与服务器时间同步
- 签名自动生成,无需手动计算
- 支持 URL 查询参数
- 自动处理 URI 路径格式
"""
# 自动判断 HTTP 方法
if method is None and json_data is None:
method = "GET"
if method is None and json_data is not None:
method = "POST"
# 处理请求体
request_body = json.dumps(json_data, separators=(',', ':')) if json_data is not None else ""
# 如果需要加密,使用公钥加密请求体
if is_encrypt and self.public_key is not None and json_data is not None:
request_body = self.encrypt_body(json_data)
# 确保 URI 以 "/" 开头
<i> if not uri.startswith("/"):</i>
uri = "/" + uri
# 构建完整 URL
url = self.base_url + uri
# 添加查询参数
<i> if params is not None:</i>
url += "?" + "&".join(f"{k}={v}" for k, v in params.items())
# 生成时间戳(毫秒级)
timestamp = int(time.time() * 1000)
# 生成签名
sign_str = self.gen_sign(
uri=uri,
version=self.version,
timestamp=timestamp,
token=self.api_key,
body=request_body,
)
# 构建请求头
headers = {
"Content-Type": "application/json",
"version": str(self.version),
"timestamp": str(timestamp),
"sign_str": sign_str,
"token": self.api_key
}
# 发送 HTTP 请求
res = requests.request(
method=method,
url=url,
data=request_body,
headers=headers
)
return res
if __name__ == "__main__":
"""
主程序入口,演示如何使用 GjRequest 类
使用前请确保:
1. 已安装必要的依赖库
2. 密钥文件路径正确
3. API 密钥有效
4. 网络连接正常
"""
# 创建 GjRequest 实例
gjRequest = GjRequest(
base_url="https://openapi.suanli.cn", # API 网关地址
api_key="984de995-3360-4426-931e-8f466d79a50a-20250813173729", # 您的 API 密钥
private_key_path="./private.key", # 私钥文件路径
public_key_path="./public.pem", # 公钥文件路径
private_key_pwd=None, # 私钥密码(如果有)
)
# 发送 GET 请求示例
response = gjRequest.request(
uri="/api/deployment/resource/search", # API 接口路径
# method="GET", # 可选:明确指定方法
# is_encrypt=False, # 可选:是否加密请求体
# params={"region": "beijing"} # 可选:URL 查询参数
)
# 打印响应结果
print(f"状态码:{response.status_code}")
print(f"响应头:{dict(response.headers)}")
print(f"响应体:{response.text}")
# POST 请求示例(带加密)
# post_response = gjRequest.request(
# uri="/api/deployment/task/create",
# method="POST",
# json_data={
# "task_name": "test-task",
# "resources": [{"mark": "resource_mark"}],
# "points": 1,
# "services": [{
# "service_name": "test-service",
# "service_image": "harbor.suanleme.cn/library/ffmpeg-api:cpu",
# "remote_ports": [{"service_port": 8000}],
# "env": None,
# "storage_config": None
# }]
# },
# is_encrypt=True # 启用请求体加密
# )

我们提供了一个完整的 GjRequest 类,封装了所有 RSA 加验签和加密功能,使用更加简单和灵活。

确保您已将完整的 Python 代码保存为 gj_request.py 文件。

将您的 RSA 密钥文件放在与 gj_request.py 相同的目录下:

  • 私钥文件private.key(必需,用于生成签名)

  • 公钥文件public.pem(必需,用于加密请求体)

打开 gj_request.py 文件,找到 if __name__ == "__main__": 部分,修改以下参数:

gjRequest = GjRequest(
base_url="https://openapi.suanli.cn", # API 网关地址
api_key="your-api-key-here", # 您的 API 密钥
private_key_path="./private.key", # 私钥文件路径
public_key_path="./public.pem", # 公钥文件路径
private_key_pwd=None, # 私钥密码(如果有)
)

参数说明:

  • base_url: API 网关基础地址
  • api_key: 平台分配的 API 密钥
  • private_key_path: RSA 私钥文件路径
  • public_key_path: RSA 公钥文件路径
  • private_key_pwd: 私钥文件密码(如果私钥未加密则为 None)

request() 方法调用中配置具体的 API 调用参数:

response = gjRequest.request(
uri="/api/deployment/resource/search", # API 接口路径
method="GET", # HTTP 方法(可选,自动判断)
is_encrypt=False, # 是否加密请求体
params={"region": "beijing"} # URL 查询参数(可选)
)
response = gjRequest.request(
uri="/api/deployment/task/create", # API 接口路径
method="POST", # HTTP 方法
json_data={ # 请求体数据
"task_name": "test-task",
"resources": [{"mark": "resource_mark"}],
"points": 1,
"services": [{
"service_name": "test-service",
"service_image": "harbor.suanleme.cn/library/ffmpeg-api:cpu",
"remote_ports": [{"service_port": 8000}],
"env": None,
"storage_config": None
}]
},
is_encrypt=True # 启用请求体加密
)

请求参数说明:

  • uri: API 接口路径,必须以 ”/” 开头
  • method: HTTP 方法(“GET” 或 “POST”),如果不指定会自动判断
  • is_encrypt: 是否加密请求体,默认 False
  • json_data: 请求体数据,JSON 格式字典
  • params: URL 查询参数,字典格式

打开终端或命令行,切换到 gj_request.py 文件所在的目录,然后运行:

Terminal window
python gj_request.py

您可以根据需要修改类中的默认配置:

class GjRequest:
# 修改默认 API 版本
version = "1.0.0" # 从 1 改为 "1.0.0"
# 添加自定义请求头
def request(self, ...):
# ... 现有代码 ...
headers = {
"Content-Type": "application/json",
"version": str(self.version),
"timestamp": str(timestamp),
"sign_str": sign_str,
"token": self.api_key,
"User-Agent": "MyApp/1.0", # 添加自定义请求头
"Accept": "application/json"
}
gj_request = GjRequest(
base_url="https://openapi.suanli.cn",
api_key="your-api-key",
private_key_path="./private.key",
public_key_path="./public.pem",
private_key_pwd=None
)
apis_to_call = [
"/api/deployment/resource/search",
"/api/deployment/task/list",
"/api/deployment/storage/list"
]
for api_path in apis_to_call:
response = gj_request.request(uri=api_path)
print(f"API: {api_path}, Status: {response.status_code}")
  1. 私钥文件未找到
  • 检查文件路径是否正确
  • 确认文件是否存在于指定目录
  1. 密钥格式错误
  • 确保密钥文件为 PEM 格式
  • 检查密钥是否损坏或格式不正确
  1. 签名验证失败
  • 检查时间戳是否与服务器同步
  • 确认 API 密钥是否正确
  • 验证请求体格式是否符合要求
import logging
logging.basicConfig(level=logging.DEBUG)
timestamp = int(time.time() * 1000)
sign_str = gj_request.gen_sign(
uri="/api/test",
version=gj_request.version,
timestamp=timestamp,
token=gj_request.api_key,
body="{}"
)
print(f"待签名字符串:/api/test\\n{gj_request.version}\\n{timestamp}\\n{gj_request.api_key}\\n{{}}")
print(f"生成的签名:{sign_str}")

在运行脚本前,确保已安装必要的 Python 库:

Terminal window
pip install cryptography requests
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
pip install cryptography requests
开始处理请求...
处理成功。
用于签名的 data_str: '{}'
计算得到的 Base64 签名字符串 (sign_str): ...
使用的时间戳 (timestamp): ...
构建的待加签原始字符串(供参考,请确保与平台逻辑一致):
---BEGIN STRING TO SIGN---
/api/deployment/resource/search
1.0.0
...
//**实际 token 字符串**
{}
---END STRING TO SIGN---
发送 API 请求至: https://openapi.suanli.cn/api/deployment/resource/search
请求方法: GET
请求头: {
"version": "1.0.0",
"timestamp": "...",
"token": "实际 token 字符串",
"sign_str": "..."
}
API 响应:
{
"code": 0,
"msg": "success",
"data": {
"device_categories": [
{
"device_name": "H20",
"region_map": {
"xingjiangf-1": {
"region": "xingjiangf-1",
"region_name": "新疆一区",
"mark": {
"resource": {
"device_name": "H20",
"region": "xingjiangf-1",
"gpu_name": "H20",
"gpu_count": 1,
"gpu_memory": 98304,
"memory": 196608,
"cpu_cores": 24
},
"region_name": null,
"mark": "ha8GDGEAORN3a9Hhu7X+W4Vtce1MVTeWkoGuBrgRNV0VuvbQPOAijLHAl\nL3THz4zxz17CQ2xan6Q2UrnIQ\n6pUPcLqpoLUCh5MaAR9kIet8llTG2oulHTzTR6DoHqgQoSFvtGpGD4Rh7S1F32ACv6i9o7EFy0RPUnKv\nTMUFPSo1heC27vZCm+ab5SZnpZiQ=="
},
"price": 2052,
"inventory": 0
},
"hebeif-1": {
"region": "hebeif-1",
"region_name": "河北一区",
"mark": {
"resource": {
"device_name": "H20",
"region": "hebeif-1",
"gpu_name": "H20",
"gpu_count": 1,
"gpu_memory": 98304,
"memory": 196608,
"cpu_cores": 24
},
"region_name": null,
"mark": "ha8GDGEAORN3a9Hhu7X+W4Vtce1MVTeWkoGuBrgRNV0ZtvTTM6x9yfvPw\nu+KYjci3wc3UkKcenSQvVqwc1\nfUVOgLm41GH3chMf1Qrz8UotFVU3Hn7xqS3D53GpC30EtfCecJ8SO4UhLT1UfiU2Oj9tokF2akCb1wba\ns+QFIKvwEvJgaT2WcPA1YY"
},
"price": 2052,
"inventory": 0
}
],
"regions": [
{
"region": "xingjiangf-1",
"region_name": "新疆一区",
"mark": {
"resource": {
"device_name": "H20",
"region": "xingjiangf-1",
"gpu_name": "H20",
"gpu_count": 1,
"gpu_memory": 98304,
"memory": 196608,
"cpu_cores": 24
},
"region_name": null,
"mark": "ha8GDGEAORN3a9Hhu7X+W4Vtce1MVTeWkoGuBrgRNV0VuvbQPOAijLHAl\nL3THz4zxz17CQ2xan6Q2UrnIQ\n6pUPcLqpoLUCh5MaAR9kIet8llTG2oulHTzTR6DoHqgQoSFvtGpGD4Rh7S1F32ACv6i9o7EFy0RPUnKv\nTMUFPSo1heC27vZCm+ab5SZnpZiQ=="
},
"price": 2052,
"inventory": 0
},

这个 JSON 数据是运行 rsa_sign_util.py 脚本后收到的 API 响应。

  • code: 状态码。0 表示 API 请求成功。
  • message: 消息字符串。"success" 进一步确认了请求成功。
  • result: 包含实际数据的结果对象。
    • total: 表示找到的资源总数。
    • resources: 这是一个列表,包含了每种资源类型的详细信息。列表中的每个对象代表一种特定的设备配置(例如 “H20 x 8”, “4090 x 8” 等)。 device_name: 设备的名称或配置。 region_mapregions: 提供该资源在不同区域的可用性和详细信息。regions 是一个列表,每个元素代表一个区域的详情。 region: 区域代码。 region_name: 区域的中文名称(例如 “浙江一区”, “福建一区”)。 mark: 包含资源规格和标记的内部对象。 price: 该资源在该区域的价格。 inventory: 该资源在该区域的库存数量。 gpu_name: 使用的 GPU 型号(例如 “H20”, “4090”)。 gpu_memory: GPU 显存大小。 gpu_count: GPU 数量。 memory: 系统内存大小。 cpu_cores: CPU 核心数。

列名

类型

是否必填

说明

实例值

version

String

API 版本

1.0.0

token

String

认证 token

sign_str

String(Base64)

签名字符串(参考加签流程)

timestamp

Integer

时间戳(毫秒)

1721299458423

参考具体接口要求。如果请求体需要加密,请参考 4.5 加密流程(先加密再计算加签字符串)。请求参考下面的示例。

Terminal window
curl --location --request POST 'https://{gateway-host}/{api-path}' \\
--header 'token: a0e13fe1-5626-4c05-926b-20f586c69102-20240821144204' \\
--header 'timestamp: 1724222524375' \\
--header 'version: 1.0.0' \\
--header 'sign_str: EowIBAAKCAQEArbNcSNSLjHzqOzrYL+7afEh5TI4hn1BCxsuzY02c1RMn24a2YEvpqCCVDxmgN/dcAdcCcvhO/2wDG389LuEkw+QhVPzdAE29bbzz+Gb/FDusVNo6tl8mbfd/XA53h3sOCekEMP2QCoPAoUO94wUWK5RpjsONf9Bs0Q6YUmL4TWqvPGmWjc/Y8winDtFzKN2his5PhbWlRiSkENGXSma6lr66BA/SduAY/Fl8YxEWThVkYsAurg0rEd83DilN4zp7hZf82Msjgp8kPm/SMHTEF2V2cOo82m12HyRJKuKS0L8WPVIwQmXJ6VN55ue+b96sryUs/WZyfiXTh0thoa9vqQIDAQABAoIBAQCsOMDQSUTPl27aKR7+b5FbVrRF7kpx3i9HUeLcG7DbJrIHHAspcTsLgrqoDR1pQC2OeXMpMP+KirqOAdtU5tAAFenijRBGY83kx0sSSHSyx/O28eTyu2ar84/oY0OqJZ0mwE1ykYXGlxlgC31zYLC5pt3+Oe/LAYlSwmjOjuhoQDMZoiCByIw6oDAVLIlZwTl8A/HAR1yacDTh6lps1vTZ5lBfIDpbn1gHb2GWqHu8q9oD9G9IEyWwwTE1IsNXVwBKEifjLubd2WfTWDmROVZZ9T4AXm/40/Eb6ALApwY5s7lBMIiapmcJZzlyELEukUMmYN7vHBjdMDOPK3tjLSKNA' \\
--data-raw '{"task_id": 1}'

列名

类型

不是 null

说明

实例值

code

String

响应 code

0000

message

String

响应说明

success

data

Object

数据体

{"task_name": "test_task1"}

  1. 生成待加签字符串:

将以下参数按照顺序用换行符 \n 连接起来:

path: 接口地址。GET 请求需要包含完整的 URL(含 query 参数)。 version: 请求头中的接口版本。 timestamp: 请求头中的时间戳(毫秒)。 token: 请求头中的 token。 data: 接口请求体。如果接口需要加密,则为加密后的 Base64 字符串。

格式示例:path\nversion\ntimestamp\ntoken\ndata

例如:/api/user/order/get_this_week_residue_withdrawal_count 1.0.0 1724222524375 a0e13fe1-5626-4c05-926b-20f586c69102-20240821144204 {"username":"test1","password":"password1"}

  1. 计算签名:

使用 RSA-SHA256 签名算法对待签名字符串进行计算,得到签名结果(字节数组)。

  1. Base64 编码:

将签名结果(字节数组)转换为 Base64 字符串。

  1. 设置请求头:

将生成的 Base64 签名字符串设置到请求头的 sign_str 字段。

  1. 根据 RSA 公钥对待发送的请求体进行 rsa_pubk_encrypt 算法加密。
  2. 将加密后的字节数组转换为 Base64 字符串。
  3. 将该 Base64 字符串作为实际的请求体发送。
  4. 如果请求同时需要加密和加签 必须先进行加密步骤,再进行加签步骤(加签时使用的 data 即为加密后的 Base64 字符串)。