认证与鉴权
本接口支持两种认证方式,建议通过开放平台配置强制使用更安全的 App Key & App Secret 认证方式。
App Key & App Secret 认证
请求示例
bash
curl "https://example.com/{path}?{query}" \
-H 'x-cy-app-key: {app_key}' \
-H 'x-cy-nonce: {nonce}' \
-H 'x-cy-timestamp: {timestamp}' \
-H 'x-cy-signature: {signature}'请求说明
认证头
- x-cy-app-key:从开放平台获取的认证凭证
- x-cy-nonce:随机字符串,长度要求 16-40 位,建议使用 UUID,每次请求不可重复
- x-cy-timestamp:请求时间的时间戳(过旧的时间戳可能会被拒绝请求)
- x-cy-signature:签名,计算方式见下文
请求参数
- path:API 请求路径
- method:HTTP 请求方法(当前仅支持 GET)
- query:请求参数
签名计算
参数排序
- 将 query 参数按字母顺序排序
- 示例:
latitude=31&longitude=121&days=1→days=1&latitude=31&longitude=121
生成签名字符串
- 按以下格式拼接:
{method}:{path}:{query}:{app_key}:{nonce}:{timestamp} - 示例:
GET:/v3/weather:days=1&latitude=31&longitude=121:your_app_key:your_nonce:your_timestamp
- 按以下格式拼接:
计算哈希值
- 对签名字符串进行 HMAC-SHA256 哈希计算,使用 app_secret 作为密钥
- 示例:
hmac_sha256(stringToSign, app_secret)
生成签名
- 使用 URL Safe Base64 对哈希值进行编码
- 示例:
base64url(sha256_result)
示例
go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
)
func Sign(
appKey string,
appSecret string,
method string,
path string,
nonce string,
timestamp int64,
query map[string]string,
) string {
// 1. 对 query 参数按字母顺序排序
keys := make([]string, 0, len(query))
for k := range query {
keys = append(keys, k)
}
sort.Strings(keys)
// 2. 构建 query 字符串(URL 编码)
var queryStr strings.Builder
for i, k := range keys {
if i > 0 {
queryStr.WriteString("&")
}
queryStr.WriteString(url.QueryEscape(k))
queryStr.WriteString("=")
queryStr.WriteString(url.QueryEscape(query[k]))
}
// 3. 构建签名字符串
stringToSign := strings.Join([]string{
method,
path,
queryStr.String(),
appKey,
nonce,
strconv.FormatInt(timestamp, 10),
}, ":")
// 4. 使用 HMAC-SHA256 计算签名
h := hmac.New(sha256.New, []byte(appSecret))
h.Write([]byte(stringToSign))
// 5. Base64 编码(URL 安全)
signature := base64.URLEncoding.EncodeToString(h.Sum(nil))
return signature
}
func main() {
appKey := "your_app_key"
appSecret := "your_app_secret"
method := http.MethodGet
path := "/v3/weather"
query := map[string]string{
"longitude": "116.3883",
"latitude": "39.9289",
"days": "1",
}
nonce := "0195c68a-42e7-7243-bff2-ac97a78b837d"
timestamp := int64(1742791910)
signature := Sign(appKey, appSecret, method, path, nonce, timestamp, query)
fmt.Println("Signature:", signature)
// Signature: YptIVeMzvihf_WeUzg0PReE-tTW5pHd9eJUYjRbvvXU=
}python
import hmac
import hashlib
import base64
import urllib.parse
from typing import Dict
def sign(
app_key: str,
app_secret: str,
method: str,
path: str,
nonce: str,
timestamp: str,
query: Dict[str, str],
) -> str:
# 1. 对 query 参数按字母顺序排序
sorted_keys = sorted(query.keys())
# 2. 构建 query 字符串(URL 编码)
query_parts = []
for k in sorted_keys:
encoded_key = urllib.parse.quote(k)
encoded_value = urllib.parse.quote(query[k])
query_parts.append(f"{encoded_key}={encoded_value}")
query_str = "&".join(query_parts)
# 3. 构建签名字符串
string_to_sign = ":".join([method, path, query_str, app_key, nonce, timestamp])
# 4. 使用 HMAC-SHA256 计算签名
h = hmac.new(app_secret.encode("utf-8"), string_to_sign.encode("utf-8"), hashlib.sha256)
# 5. Base64 编码(URL 安全)
signature = base64.urlsafe_b64encode(h.digest()).decode("utf-8")
return signature
# 示例使用
app_key = "your_app_key"
app_secret = "your_app_secret"
method = "GET"
path = "/v3/weather"
query = {
"longitude": "116.3883",
"latitude": "39.9289",
"days": "1"
}
nonce = "0195c68a-42e7-7243-bff2-ac97a78b837d"
timestamp = "1742791910"
signature = sign(app_key, app_secret, method, path, nonce, timestamp, query)
print(f"Signature: {signature}")
# Signature: YptIVeMzvihf_WeUzg0PReE-tTW5pHd9eJUYjRbvvXU=javascript
const crypto = require("crypto");
function sign(appKey, appSecret, method, path, nonce, timestamp, query) {
// 1. 对 query 参数按字母顺序排序
const sortedKeys = Object.keys(query).sort();
// 2. 构建 query 字符串(URL 编码)
const queryStr = sortedKeys
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`)
.join("&");
// 3. 构建签名字符串
const stringToSign = [
method,
path,
queryStr,
appKey,
nonce,
timestamp.toString(),
].join(":");
// 4. 使用 HMAC-SHA256 计算签名
const hmac = crypto.createHmac("sha256", appSecret);
hmac.update(stringToSign);
// 5. Base64 编码(URL 安全)
const signature = hmac
.digest("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_");
return signature;
}
// 示例使用
const appKey = "your_app_key";
const appSecret = "your_app_secret";
const method = "GET";
const path = "/v3/weather";
const query = {
longitude: "116.3883",
latitude: "39.9289",
days: "1",
};
const nonce = "0195c68a-42e7-7243-bff2-ac97a78b837d";
const timestamp = 1742791910;
const signature = sign(appKey, appSecret, method, path, nonce, timestamp, query);
console.log("Signature:", signature);
// Signature: YptIVeMzvihf_WeUzg0PReE-tTW5pHd9eJUYjRbvvXU=java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class ApiSignature {
public static String sign(
String appKey,
String appSecret,
String method,
String path,
String nonce,
long timestamp,
Map<String, String> query
) throws Exception {
// 1. 对 query 参数按字母顺序排序
Map<String, String> sortedQuery = new TreeMap<>(query);
// 2. 构建 query 字符串(URL 编码)
String queryStr = sortedQuery.entrySet().stream()
.map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) +
"=" +
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
// 3. 构建签名字符串
String stringToSign = String.join(":",
method,
path,
queryStr,
appKey,
nonce,
String.valueOf(timestamp)
);
// 4. 使用 HMAC-SHA256 计算签名
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
appSecret.getBytes(StandardCharsets.UTF_8),
"HmacSHA256"
);
hmac.init(secretKey);
byte[] signatureBytes = hmac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
// 5. Base64 编码(URL 安全)
String signature = Base64.getUrlEncoder().encodeToString(signatureBytes);
return signature;
}
public static void main(String[] args) throws Exception {
String appKey = "your_app_key";
String appSecret = "your_app_secret";
String method = "GET";
String path = "/v3/weather";
Map<String, String> query = new TreeMap<>();
query.put("longitude", "116.3883");
query.put("latitude", "39.9289");
query.put("days", "1");
String nonce = "0195c68a-42e7-7243-bff2-ac97a78b837d";
long timestamp = 1742791910;
String signature = sign(appKey, appSecret, method, path, nonce, timestamp, query);
System.out.println("Signature: " + signature);
// Signature: YptIVeMzvihf_WeUzg0PReE-tTW5pHd9eJUYjRbvvXU=
}
}Token 认证(不建议)
WARNING
Token 认证方式有泄漏风险,建议使用 App Key & App Secret 认证方式。
支持以下两种 Token 传递方式:
bash
curl "https://example.com/xxxx?token={token}"bash
curl "https://example.com" \
-H 'Authorization: Bearer {token}'