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