QCS开放接口文档

QCS开放接口文档

QCS(QSL认证系统,QSL Certification System)对外开放接口文档:

基础信息

API地址

https://qcs.qsl.pub/api

基础响应模块

/**
 * API响应通用类型定义
 * @template T - 响应数据的类型
 */
export interface ApiResponse<T> {
  /** 响应数据 */
  data: T;
  /** 状态码 */
  code: number;
  /** 消息提示 */
  msg: string;
}

code状态码

状态码 描述
200 正常返回
500 系统错误
401 未授权
404 找不到资源

默认请求数据类型

application/json

默认响应数据类型

json

通用数据结构

StationItem

参数名称 参数说明 数据类型
id 台站ID number
callsign 呼号 string
dxcc DXCC实体 string
grid 网格 string
itu ITU区域 string
cq CQ区域 string
station_location 台站位置 string
first_qso_date 首次QSO时间(毫秒时间戳) number
last_qso_date 最后QSO时间(毫秒时间戳) number | null

QsoList

参数名称 参数说明 是否必须 数据类型
callsign 对方呼号 true string
worked 我的呼号 true string
date 通联时间(时间戳) true number
mode 模式 true string
band 接收波段 true string
band_tx 发送波段 false string
freq 接收频率 true number
freq_tx 发送频率 false number
rst_rcvd 接收RST true string
rst_sent 发送RST true string
satellite 卫星名称 false string
propagation 传播模式 false string

OAuth模块

OAuth模块部分数据使用签名+加密传输。调用受保护接口时需要在请求头中携带:

Authorization: Bearer <access_token>

建议按以下顺序接入:获取授权码 -> 获取Token -> 刷新Token -> 调用资源接口。

OAuth授权码模式说明

  • 当前仅支持 response_type=code
  • 授权请求必须携带 state
  • 当前支持两种 PKCE 方法:S256SM3
  • 授权码与 client_idredirect_uriscopecode_challenge 绑定
  • 换取 token 时,必须提交原始 code_verifier

获取授权码

QCS 使用授权页完成用户登录、授权确认与授权码签发。第三方客户端应将用户浏览器跳转到 QCS 授权地址,并携带以下查询参数:

参数名称 参数说明 是否必须 数据类型
client_id 客户端ID true string
redirect_uri 回调地址,必须与应用登记值完全一致 true string
response_type 固定为 code true string
scope 申请的权限范围,逗号分隔 true string
state 客户端生成的随机态值,用于回调校验 true string
code_challenge PKCE 挑战值 true string
code_challenge_method PKCE 方法,支持 S256 / SM3 true string

授权成功后,QCS 将通过 redirect_uri 回跳并附带:

参数名称 参数说明 数据类型
code 授权码 string
state 原样回传的 state string

scope取值

scope 说明
basic 读取基础信息(openid、callsign)
station 读取台站列表
qsl 读取QSL统计信息
qso 导入QSO记录

获取Token

POST /oauth/token

请求说明

  • 外层请求体使用“先 SM4-GCM 加密,再 SM2withSM3 签名”的方式传输
  • code 作为外层明文字段传输
  • data 中的 code 需与外层 code 保持一致

请求参数

参数名称 参数说明 是否必须 数据类型
code 授权码(明文) true string
iv GCM 初始向量,base64;解码后为 12 字节随机值 true string
data 加密后的明文请求体,base64 true string
authtag GCM 认证标签,base64 true string
signature 签名值 true string
timestamp 时间戳(秒) true number
nonce 随机字符串 true string
data(明文解密后)
参数名称 参数说明 是否必须 数据类型
client_id 客户端ID true string
client_secret 客户端密钥 true string
code 授权码,必须与外层 code 一致 true string
redirect_uri 回调地址,必须与授权时一致 true string
code_verifier PKCE 原始校验串 true string

响应参数

响应体同样使用签名 + SM4-GCM 加密;客户端需先验签,再按同一组参数解密。明文结构如下:

参数名称 参数说明 数据类型
access_token 访问令牌 string
refresh_token 刷新令牌 string
token_type 固定为 Bearer string
expires_in 过期时间戳(秒) number

刷新Token

POST /oauth/refresh_token

请求头

Authorization: Bearer <refresh_token>

说明

  • refresh token 为一次性轮换凭证
  • 刷新成功后,旧 refresh token 立即失效
  • 客户端必须使用响应中的新 refresh token 覆盖本地旧值

响应参数

响应格式与 /oauth/token 相同,明文结构也相同。

请求说明

  • 使用 refresh_token 作为 Bearer Token 调用
  • 刷新成功后,旧 refresh token 立即失效
  • 新的 access token / refresh token 会一起返回

获取用户信息

POST /oauth/userinfo

scope

basic

请求头

Authorization: Bearer <access_token>

请求说明

  • 响应体使用签名 + SM4-GCM 加密

响应参数(明文解密后)

参数名称 参数说明 数据类型
openid 当前用户的 OAuth openid string
callsign 当前用户呼号 string

获取QSL统计信息

POST /oauth/qsl_info

scope

qsl

请求头

Authorization: Bearer <access_token>

请求说明

  • 响应体使用签名 + SM4-GCM 加密

响应参数(明文解密后)

参数名称 参数说明 数据类型
worked 主呼号 string
qso_total QSO总数 number
qsl_total QSL总数 number
latest_qsl_hash 最新QSL哈希 string | null
latest_qsl_date 最新QSL时间,毫秒时间戳 number | null

获取台站列表(OAuth)

POST /oauth/get_station_list

scope

station

请求头

Authorization: Bearer <access_token>

请求说明

  • 响应体使用签名 + SM4-GCM 加密

响应参数(明文解密后)

响应为 StationItem[]

导入QSO记录(OAuth)

POST /oauth/push_qso

scope

qso

请求说明

  • 请求体使用签名 + SM4-GCM 加密
  • data 解密后应为导入结构体 JSON

请求参数

参数名称 参数说明 是否必须 数据类型 schema
iv 加密向量(base64) true string
data 加密后的密文(base64) true string data
authtag GCM认证标签(base64) true string
signature 签名值 true string
timestamp 时间戳(秒) true number
nonce 随机字符串 true string
data(明文解密后)
参数名称 参数说明 是否必须 数据类型 schema
station_id 台站id true number
qso_list qso列表 true QsoList[] QsoList

请求示例

{
  "iv": "...",
  "data": "...",
  "authtag": "...",
  "signature": "...",
  "timestamp": 1735660800,
  "nonce": "..."
}

响应示例

{
  "data": {
    "iv": "...",
    "data": "...",
    "authtag": "...",
    "signature": "...",
    "timestamp": 1735660800,
    "nonce": "..."
  },
  "code": 200,
  "msg": "success"
}

加密签名与验签解密

OAuth 加密接口(如 /oauth/token/oauth/userinfo/oauth/get_station_list/oauth/qsl_info/oauth/push_qso)统一采用同一套报文约定。

1. 整体流程

  • 发送方先组装明文 JSON,再使用 SM4-GCM 加密,最后对密文做 SM2withSM3 签名
  • 接收方先校验 timestampnoncesignature,验签通过后再执行 SM4-GCM 解密
  • 请求与响应都遵循这一流程,只是双方使用的 SM2 密钥方向不同

2. 字段说明

字段 说明
iv Base64 字符串,解码后必须为 12 字节随机值
data 业务明文经 SM4-GCM 加密后的密文,Base64 编码
authtag SM4-GCM 认证标签,Base64 编码
signature data|timestamp|nonce 进行 SM2withSM3 签名后的结果
timestamp 秒级 Unix 时间戳
nonce 每次请求/响应唯一的随机字符串,用于防重放
sn 对称密钥编号,参与 AAD 计算;无编号时使用空字符串

3. 明文封装格式

加密前,明文统一封装为:

{
  "data": { ...业务数据... },
  "_n": "<nonce>",
  "_appid": "<appid>",
  "_timestamp": 1735660800
}

其中:

  • data 为真实业务数据
  • _appid 必须与当前客户端 appid 一致
  • _timestamp 必须与外层 timestamp 一致
  • _n 建议与外层 nonce 保持一致

4. SM4-GCM 加密参数

  • 对称算法:SM4-GCM
  • 密钥:16 字节 SM4 密钥,接口传输和配置中统一使用 Base64 表示
  • iv:12 字节随机值,Base64 编码后放入 iv
  • authtag:GCM 输出的认证标签,Base64 编码后放入 authtag
  • AAD 固定为:
{urlpath}|{appid}|{timestamp}|{sn}

说明:

  • urlpath 为接口路径本身,例如 /oauth/token
  • appid 为客户端 client_id
  • timestamp 必须与报文外层字段一致
  • sn 为对称密钥编号;如果接口场景没有编号,则传空字符串参与拼接

只要 urlpathappidtimestampsn 任一项不一致,都会导致解密或认证失败。

5. 签名规则

签名原文固定为:

{data}|{timestamp}|{nonce}

签名说明:

  • data 指加密后的密文字段,不是明文 JSON
  • timestampnonce 取报文外层字段
  • 签名算法为 SM2withSM3

5.1 SM2withSM3 兼容性要求

为避免不同语言/不同国密库之间互通失败,OAuth 模块在签名验签时建议按以下固定配置接入:

  • 签名算法:SM2withSM3
  • 公钥格式:未压缩公钥,04 开头的 130 位 Hex 字符串
  • 私钥格式:32 字节私钥的 Hex 字符串
  • 签名输出格式:推荐使用 DER 编码后再做 Base64
  • 验签输入格式:推荐使用 DER 签名;当前接口兼容 DER 签名和 64 字节原始签名
  • 用户标识(distid / userId):固定为默认值 1234567812345678

其中签名值在本系统中的实际传输格式为:

Base64(DER(signature))

也就是说:

  • 签名时,先生成 SM2 签名结果
  • 将签名按 DER 编码
  • 再将 DER 二进制做 Base64,作为 signature 字段传输

如果你的 SDK 支持“原始 64 字节签名”和“DER 编码签名”两种模式,优先选择 DER

5.2 常见 SDK 配置提示

不同 SDK 的参数名可能不同,但语义建议对齐为:

  • hash = trueuseSm3 = true
  • der = true
  • userId / distId / id = "1234567812345678"
  • 如果存在 cipherMode,在签名场景可忽略;在 SM2 加密场景建议选择 C1C3C2

JavaScript 接入推荐使用 sm-crypto-v2 国密库,签名常见写法可参考:

sign(data, privateKey, {
  hash: true,
  der: true,
})
// userId 默认即可

验签则保持同样的 hash/userId/der 语义。

6. 请求方向的密钥使用

客户端调用 QCS 加密接口时:

  • 使用协商好的 SM4 密钥加密请求体
  • 使用客户端自己的 SM2 私钥生成 signature
  • QCS 使用客户端登记的 SM2 公钥验签

7. 响应方向的密钥使用

QCS 返回加密响应时:

  • 使用同一把 SM4 密钥加密响应体
  • 使用 QCS 平台 SM2 私钥生成 signature
  • 客户端使用 QCS 平台 SM2 公钥验签

8. 接入建议

  • 先固定一套测试参数,单独验证“加密 -> 签名 -> 验签 -> 解密”链路
  • 优先确保 urlpath 与实际请求路径完全一致,包含前导 /
  • 所有 Base64 字段均使用标准 Base64,不要混用 Base64URL
  • nonce 每次请求都重新生成,不要复用
  • 客户端与服务端时间应保持同步,避免因时钟漂移导致 timestamp 校验失败

PAT模块

PAT(Personal Access Token,个人访问令牌)由 QCS 个人中心创建并管理,对外仅开放使用接口。

  • PAT 只能在创建时明文返回一次,请客户端自行安全保存
  • push_qso_by_token 的业务数据使用 SM4-CBC + PKCS#7 加密,PAT 原文直接作为对称密钥使用

PAT加密传输约定

PAT 模式仅对业务数据做对称加密。

1. 整体流程

  • 客户端持有 PAT 原文
  • 调用方使用 PAT 原文作为 SM4-CBC 的密钥加密业务 JSON
  • 请求时直接在 token 字段中传入 PAT 原文

2. 加密规则

  • 对称算法:SM4-CBC
  • 填充方式:PKCS#7
  • 密钥:PAT 原文
  • iv:16 字节随机值,Base64 编码后放入请求体 iv
  • data:业务 JSON 加密后的密文,Base64 编码

3. 注意事项

  • iv 必须每次重新生成,不能复用
  • token 必须传 PAT 原文,不能传哈希值或掩码值
  • tokenivdata 需保持匹配

获取QCS台站列表

POST /oauth/personal_access_tokens/get_station_list

请求参数

参数名称 参数说明 是否必须 数据类型
token QCS 个人中心获取的 PAT true string

请求说明

  • 该接口不需要 OAuth access token
  • 直接使用 PAT 访问

请求示例

{
  "token": "MTIzNDU2"
}

响应参数

响应为 StationItem[]

响应示例

{
  "data": [
    {
      "id": 1,
      "callsign": "BG7ZAG",
      "dxcc": "83",
      "grid": "OL50da",
      "itu": "44",
      "cq": "24",
      "station_location": "中国-海南",
      "first_qso_date": 1735660800000,
      "last_qso_date": null
    }
  ],
  "code": 200,
  "msg": "success"
}

导入QSO记录(PAT)

POST /oauth/personal_access_tokens/push_qso_by_token

请求参数

参数名称 参数说明 是否必须 数据类型 schema
token QCS 个人中心获取的 PAT true string
iv 加密向量(16字节随机IV转 base64) true string
data 加密数据(json字符串密文) true string data

请求说明

  • 该接口不需要 OAuth access token
  • data 使用 SM4-CBC + PKCS#7 加密
  • 解密密钥直接使用 PAT 原文
  • iv 为 16 字节随机值的 Base64 表示
data
参数名称 参数说明 是否必须 数据类型 schema
station_id 台站id true number
qso_list qso列表 true QsoList[] QsoList

请求示例

{
  "token": "MTIzNDU2",
  "iv": "w==",
  "data": "..."
}
const data = {
  station_id: 1,
  qso_list: [
    {
      callsign: "BG7ZAG",
      worked: "BG7ZAG",
      date: 1735660800000,
      mode: "SSB",
      band: "160m",
      freq: 160000000,
      rst_rcvd: "59",
      rst_sent: "59",
      satellite: null,
      propagation: null
    }
  ]
}

响应示例

{
  "data": "提交成功",
  "code": 200,
  "msg": "success"
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇