API 授權(quán)與驗(yàn)證
快代理 API 會對每個訪問請求進(jìn)行身份驗(yàn)證,即每個請求都需要包含簽名信息(signature參數(shù))以驗(yàn)證請求者身份。 簽名信息由API密鑰生成,密鑰包括 SecretId 和 SecretKey;每個訂單都有對應(yīng)的API密鑰,API密鑰相當(dāng)于調(diào)用API的密碼,一定要嚴(yán)格保密謹(jǐn)防泄露。
必須使用https調(diào)用接口
https加密傳輸可讓API調(diào)用信息不被第三方監(jiān)聽和截獲,更加安全。使用https只需保證API鏈接以https://開頭。
簽名驗(yàn)證方式
我們提供兩種簽名方式供您選擇:
- 密鑰令牌驗(yàn)證(默認(rèn))
- 數(shù)字簽名驗(yàn)證
您可以根據(jù)自己的業(yè)務(wù)需要選擇合適的簽名驗(yàn)證方式。下面是對兩種驗(yàn)證方式的詳細(xì)說明。
密鑰令牌驗(yàn)證
參數(shù)設(shè)置:sign_type=token
密鑰令牌驗(yàn)證即提前調(diào)用get_secret_token接口獲取密鑰令牌(secret_token),將獲取到的secret_token直接用作簽名(signature)。
此驗(yàn)證方式非常簡單,適合希望快速接入,不需要防篡改、防重放的開發(fā)者(需要防篡改、防重放請使用數(shù)字簽名驗(yàn)證)。
關(guān)于令牌有效期
密鑰令牌默認(rèn)有效期為60分鐘,您可以在會員中心-API設(shè)置里修改。
開發(fā)建議:
- 您不必每次調(diào)用接口前都獲取令牌,建議您本地保存獲取到的secret_token,在合適的時候調(diào)用get_secret_token接口再次獲取密鑰令牌。
- 您可以隨時調(diào)用check_secret_token接口檢查token有效性。
簽名參數(shù)示例
signature=oxf0n0g59h7wcdyvz2uo68ph2s
使用示例:
以調(diào)用獲取訂單到期時間接口為例,當(dāng)用戶調(diào)用這一接口時,其請求參數(shù)可能如下:
| 參數(shù) | 參數(shù)說明 | 參數(shù)值 |
|---|---|---|
| secret_id | 訂單SecretId | o1fjh1re9o28876h7c08 |
| sign_type | 鑒權(quán)方式 | token |
-
調(diào)用get_secret_token接口獲取密鑰令牌:
secret_token: oxf0n0g59h7wcdyvz2uo68ph2s
-
直接將獲取到的secret_token作為簽名(signature)參數(shù)生成api鏈接:
https://dev.kdlapi.com/api/getorderexpiretime? sign_type=token&secret_id=o1fjh1re9o28876h7c08×tamp=1555080775&signature=oxf0n0g59h7wcdyvz2uo68ph2s
數(shù)字簽名驗(yàn)證
參數(shù)設(shè)置:sign_type=hmacsha1
數(shù)字簽名驗(yàn)證方式通過將調(diào)用參數(shù)+時間戳+隨機(jī)數(shù)(可選)用SecretKey計(jì)算出簽名進(jìn)行驗(yàn)證,具有安全性好,防篡改、防重放的特點(diǎn)。
簽名參數(shù)示例
sign_type=hmacsha1×tamp=1555080775&signature=ooCUlI6XTxoPS5PG8gNMT37YVl4%3D
我們采用HMAC-SHA1方式進(jìn)行數(shù)字簽名,接下來對生成簽名參數(shù)的步驟做一個詳細(xì)介紹。
1. 生成簽名串
以下是生成簽名串的詳細(xì)過程:
會員中心API密鑰管理頁得到訂單的SecretId和SecretKey:
- SecretId:
o1fjh1re9o28876h7c08 - SecretKey:
jd1gzm6ant2u7pojhbtl0bam0xpzsm1c
注意: 上述取值只是示例,請根據(jù)您實(shí)際的 SecretId 和 SecretKey 進(jìn)行后續(xù)操作!
以調(diào)用獲取訂單到期時間接口為例,當(dāng)用戶調(diào)用這一接口時,其請求參數(shù)可能如下:
| 參數(shù) | 參數(shù)說明 | 參數(shù)值 |
|---|---|---|
| secret_id | 訂單SecretId | o1fjh1re9o28876h7c08 |
| sign_type | 鑒權(quán)方式 | hmacsha1 |
| timestamp | 當(dāng)前時間戳 | 1555064362 |
1.1 對參數(shù)排序
首先對所有請求參數(shù)按參數(shù)名的字典序( ASCII 碼)升序排序。注意:
1)只按參數(shù)名進(jìn)行排序,參數(shù)值保持對應(yīng)即可,不參與比大??;
2)按 ASCII 碼比大小,不是按字母表,也不是按數(shù)值。用戶可以借助編程語言中的相關(guān)排序函數(shù)來實(shí)現(xiàn)這一功能,如 php 中的 ksort 函數(shù)。
上述示例參數(shù)的排序結(jié)果如下:
{
"secret_id": "o1fjh1re9o28876h7c08",
"sign_type": "hmacsha1",
"timestamp": 1555064362,
}
使用其它程序設(shè)計(jì)語言開發(fā)時,可對上面示例中的參數(shù)進(jìn)行排序,得到的結(jié)果一致即可。
1.2 拼接請求字符串
此步驟生成請求字符串。 將把上一步排序好的請求參數(shù)格式化成“參數(shù)名稱”=“參數(shù)值”的形式,如對 SecretId 參數(shù),其參數(shù)名稱為 "secret_id" ,參數(shù)值為 "o1fjh1re9o28876h7c08" ,因此格式化后就為 secret_id=o1fjh1re9o28876h7c08 。
注意: “參數(shù)值”為原始值而非url編碼后的值。
然后將格式化后的各個參數(shù)用"&"拼接在一起,最終生成的請求字符串為:
secret_id=o1fjh1re9o28876h7c08&sign_type=hmacsha1×tamp=1555069980
1.3 拼接簽名原文字符串
此步驟生成簽名原文字符串。 簽名原文字符串由以下幾個參數(shù)構(gòu)成:
- 請求方法: 支持 POST 和 GET 方式,這里使用 GET 請求,注意方法為全大寫。
- 請求路徑: 例如獲取訂單到期時間的請求路徑為:
/api/getorderexpiretime。實(shí)際的請求路徑根據(jù)接口的不同而不同,詳見各接口描述。 - 請求字符串: 即上一步生成的請求字符串。
簽名原文串的拼接規(guī)則為: 請求方法 + 請求路徑 + ? + 請求字符串
示例的拼接結(jié)果為:
GET/api/getorderexpiretime?secret_id=o1fjh1re9o28876h7c08&sign_type=hmacsha1×tamp=1555069980
1.4 生成簽名串
此步驟生成簽名串。首先使用 HMAC-SHA1 算法對上一步中獲得的簽名原文字符串進(jìn)行簽名,然后將生成的簽名串使用 Base64 進(jìn)行編碼,即可獲得最終的簽名串。
具體代碼如下,以 PHP 語言為例:
<?php
$secretKey = 'jd1gzm6ant2u7pojhbtl0bam0xpzsm1c';
$rawStr = 'GET/api/getorderexpiretime?secret_id=o1fjh1re9o28876h7c08&sign_type=hmacsha1×tamp=1555069980';
$signStr = base64_encode(hash_hmac('sha1', $rawStr, $secretKey, true));
echo $signStr;
最終得到的簽名串為:
ooCUlI6XTxoPS5PG8gNMT37YVl4=
使用其它程序設(shè)計(jì)語言開發(fā)時,可用上面示例中的原文進(jìn)行簽名驗(yàn)證,得到的簽名串與例子中的一致即可。
1.5 簽名串編碼
生成的簽名串并不能直接作為請求參數(shù),需要對其進(jìn)行 URL 編碼。
如上一步生成的簽名串為ooCUlI6XTxoPS5PG8gNMT37YVl4=,最終得到的簽名串請求參數(shù)(signature)為 ooCUlI6XTxoPS5PG8gNMT37YVl4%3D, 它將用于生成最終的api鏈接。
提示
-
如果用戶的請求方法是 GET,或者請求方法為 POST 同時 Content-Type 為 application/x-www-form-urlencoded,則發(fā)送請求時所有請求參數(shù)的值均需要做 URL 編碼,參數(shù)鍵和=符號不需要編碼。非 ASCII 字符在 URL 編碼前需要先以 UTF-8 進(jìn)行編碼。
-
有些編程語言的 http 庫會自動為所有參數(shù)進(jìn)行 urlencode,在這種情況下,就不需要對簽名串進(jìn)行 URL 編碼了,否則兩次 URL 編碼會導(dǎo)致簽名失敗。
-
其他參數(shù)值也需要進(jìn)行編碼,編碼采用 RFC 3986。使用 %XY 對特殊字符例如漢字進(jìn)行百分比編碼,其中“X”和“Y”為十六進(jìn)制字符(0-9 和大寫字母 A-F),使用小寫將引發(fā)錯誤。
1.6 生成api鏈接示例
以getorderexpiretime接口為例,最終輸出api鏈接為:
https://dev.kdlapi.com/api/getorderexpiretime?
sign_type=hmacsha1&secret_id=o1fjh1re9o28876h7c08×tamp=1555080775&signature=ooCUlI6XTxoPS5PG8gNMT37YVl4%3D
溫馨提示
由于示例中的密鑰是虛構(gòu)的,時間戳也不是系統(tǒng)當(dāng)前時間。為了得到一個可以正常返回的 url ,需要修改示例中的 secret_id 和 secret_key 為真實(shí)訂單的密鑰信息,并使用系統(tǒng)當(dāng)前時間戳作為 timestamp 。
在實(shí)際調(diào)用 API 時,推薦使用配套的SDK,SDK 封裝了簽名的過程,開發(fā)時只關(guān)注產(chǎn)品提供的具體接口即可。詳細(xì)信息參見 SDK中心。
2. 代碼示例
提示
- 在下面的示例中,不同編程語言,甚至同一語言每次執(zhí)行得到的 url 可能都有所不同,表現(xiàn)為參數(shù)的順序不同,但這并不影響正確性。只要所有參數(shù)都在,且簽名計(jì)算正確即可。
- 其他語言示例請參考 代碼樣例-數(shù)字簽名 (sdk_hmacsha1)
Python示例
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import time
import base64
import hashlib
import hmac
import requests
class Auth:
"""用于保存用戶secret_id、secret_key,以及計(jì)算簽名的對象。"""
def __init__(self, secret_id, secret_key):
self.secret_id = secret_id
self.secret_key = secret_key
@classmethod
def get_string_to_sign(cls, method, endpoint, params):
""" 生成簽名原文字符串 """
s = method + endpoint.split('.com')[1] + '?'
query_str = '&'.join("%s=%s" % (k, params[k]) for k in sorted(params))
return s + query_str
def sign_str(self, raw_str, method=hashlib.sha1):
""" 生成簽名串 """
try:
hmac_str = hmac.new(self.secret_key.encode('utf8'), raw_str.encode('utf8'), method).digest()
except UnicodeDecodeError as e:
hmac_str = hmac.new(self.secret_key.encode('utf8'), raw_str, method).digest()
return base64.b64encode(hmac_str)
def _get_base_res(method, endpoint, params):
"""處理基礎(chǔ)請求,
若響應(yīng)為json格式則返回請求結(jié)果dict
否則直接返回原格式
"""
try:
r = None
if method == "GET":
r = requests.get("https://" + endpoint, params=params)
elif method == "POST":
r = requests.post("https://" + endpoint, data=params)
if r.status_code != 200:
return 'HTTP Status Code: %s' % r.status_code
try:
return json.loads(r.content.decode('utf8'))
except ValueError as e: # 返回結(jié)果不是json格式, 直接返回
return r.content.decode('utf8')
except Exception as e:
print(str(e))
if __name__ == '__main__':
secret_id = 'o1fjh1re9o28876h7c08'
secret_key = 'jd1gzm6ant2u7pojhbtl0bam0xpzsm1c'
method = 'GET' # 請求方式
endpoint = 'dev.kdlapi.com/api/getorderexpiretime'
# 除signature外的所有參數(shù)都放入params
params = {
'secret_id': secret_id,
'sign_type': 'hmacsha1',
'timestamp': int(time.time()),
}
auth = Auth(secret_id, secret_key)
raw_str = auth.get_string_to_sign(method, endpoint, params)
params['signature'] = auth.sign_str(raw_str)
res = _get_base_res(method, endpoint, params)
print(res)
3. SDK下載
通過sdk封裝了簽名計(jì)算過程,讓您免去了這部分的編程工作,配置好apikey即可調(diào)用。