Skip to content

认证与鉴权

本接口支持两种认证方式,建议通过开放平台配置强制使用更安全的 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}'

请求说明

  1. 认证头

    • x-cy-app-key:从开放平台获取的认证凭证
    • x-cy-nonce:随机字符串,长度要求 16-40 位,建议使用 UUID,每次请求不可重复
    • x-cy-timestamp:请求时间的时间戳(过旧的时间戳可能会被拒绝请求)
    • x-cy-signature:签名,计算方式见下文
  2. 请求参数

    • path:API 请求路径
    • method:HTTP 请求方法(当前仅支持 GET)
    • query:请求参数

签名计算

  1. 参数排序

    • 将 query 参数按字母顺序排序
    • 示例:latitude=31&longitude=121&days=1days=1&latitude=31&longitude=121
  2. 生成签名字符串

    • 按以下格式拼接:{method}:{path}:{query}:{app_key}:{nonce}:{timestamp}
    • 示例:GET:/v3/weather:days=1&latitude=31&longitude=121:your_app_key:your_nonce:your_timestamp
  3. 计算哈希值

    • 对签名字符串进行 HMAC-SHA256 哈希计算,使用 app_secret 作为密钥
    • 示例:hmac_sha256(stringToSign, app_secret)
  4. 生成签名

    • 使用 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}'