API 授权与验证
快代理 API 会对每个访问请求进行身份验证,即每个请求都需要包含签名信息(signature参数)以验证请求者身份。 签名信息由安全凭证生成,安全凭证包括 订单号(orderid) 和 API Key;每个订单都有对应的API Key,API Key相当于调用API的密码,一定要严格保密谨防泄露。
开启接口验证
为了兼容之前的API链接,提取开放代理、提取私密代理、提取独享代理、提取隧道代理4个接口,默认需要验证,生成的API链接可以直接使用。
其他接口必须验证签名才能调用。
我们推荐在会员中心对4个代理提取接口也开启验证。
开启验证的好处是即使别人拿到订单号,也无法使用API,安全性大大增强。
建议使用https调用接口
我们强烈建议您使用https调用API,加密传输可让订单号、API Key等私密信息不被第三方监听和截获,更加安全。
使用https只需将API链接开头的http://
替换为https://
即可。
签名验证机制
我们提供两种签名机制供您选择:
- 密钥明文验证(默认)
- 数字签名验证
您可以根据自己的业务需要选择任意一种进行签名验证。下面是对两种验证机制的详细说明。
密钥明文验证
参数设置:sign_type=simple
密钥明文验证非常简单,适合希望快速接入,对安全性没有非常高要求的开发者。
使用密钥明文验证,直接把API Key放到signature
参数里即可。在会员中心查看订单的API Key,比如您订单的API Key是oeq1zxnmoxzlefzmjrqu2xufwndod7kz
,API链接的签名参数即为signature=oeq1zxnmoxzlefzmjrqu2xufwndod7kz
。
签名参数示例
signature=oeq1zxnmoxzlefzmjrqu2xufwndod7kz
数字签名验证
参数设置:sign_type=hmacsha1
数字签名验证机制更为复杂,适合对安全性有高要求的开发者。
签名参数示例
sign_type=hmacsha1×tamp=1555080775&signature=%2bhLAH7Rlyoq3SSB2xUbzGpyOZn4%3d
我们采用HMAC-SHA1方式进行数字签名,接下来对生成签名参数的步骤做一个详细介绍。
1. 生成签名串
以下是生成签名串的详细过程:
假设用户的orderId
和apiKey
分别是:
- orderId: 934995977901561
- apiKey: u8n5a0f2hu39o80lpir3hq1kug37tb5i
注意: 这里只是示例,请根据用户实际的 orderId
和 apiKey
进行后续操作!
以获取订单到期时间请求为例,当用户调用这一接口时,其请求参数可能如下:
参数名称 | 中文 | 参数值 |
---|---|---|
orderid | 订单号 | 934995977901561 |
sign_type | 鉴权方式 | hmacsha1 |
timestamp | 当前时间戳 | 1555064362 |
1.1 对参数排序
首先对所有请求参数按参数名的字典序( ASCII 码)升序排序。注意:
1)只按参数名进行排序,参数值保持对应即可,不参与比大小;
2)按 ASCII 码比大小,如 InstanceIds.2 要排在 InstanceIds.12 后面,不是按字母表,也不是按数值。用户可以借助编程语言中的相关排序函数来实现这一功能,如 php 中的 ksort 函数。
上述示例参数的排序结果如下:
{
"orderid": "954763036233510",
"sign_type": "hmacsha1",
"timestamp": 1555064362,
}
使用其它程序设计语言开发时,可对上面示例中的参数进行排序,得到的结果一致即可。
1.2 拼接请求字符串
此步骤生成请求字符串。 将把上一步排序好的请求参数格式化成“参数名称”=“参数值”的形式,如对 orderid 参数,其参数名称为 "orderid" ,参数值为 "954763036233510" ,因此格式化后就为 orderid=954763036233510 。
注意: “参数值”为原始值而非url编码后的值。
然后将格式化后的各个参数用"&"拼接在一起,最终生成的请求字符串为:
orderid=954763036233510&sign_type=hmacsha1×tamp=1555069980
1.3 拼接签名原文字符串
此步骤生成签名原文字符串。 签名原文字符串由以下几个参数构成:
- 请求方法: 支持 POST 和 GET 方式,这里使用 GET 请求,注意方法为全大写。
- 请求路径: 例如获取订单到期时间的请求路径为:
/api/getorderexpiretime
。实际的请求路径根据接口的不同而不同,详见各接口描述。 - 请求字符串: 即上一步生成的请求字符串。
签名原文串的拼接规则为: 请求方法 + 请求路径 + ? + 请求字符串
示例的拼接结果为:
GET/api/getorderexpiretime?orderid=954763036233510&sign_type=hmacsha1×tamp=1555069980
1.4 生成签名串
此步骤生成签名串。首先使用 HMAC-SHA1
算法对上一步中获得的签名原文字符串进行签名,然后将生成的签名串使用 Base64 进行编码,即可获得最终的签名串。
具体代码如下,以 PHP 语言为例:
<?php
$apiKey = 'u8n5a0f2hu39o80lpir3hq1kug37tb5i';
$rawStr = 'GET/api/getorderexpiretime?orderid=954763036233510&sign_type=hmacsha1×tamp=1555069980';
$signStr = base64_encode(hash_hmac('sha1', $rawStr, $apiKey, true));
echo $signStr;
最终得到的签名串为:
+hLAH7Rlyoq3SSB2xUbzGpyOZn4=
使用其它程序设计语言开发时,可用上面示例中的原文进行签名验证,得到的签名串与例子中的一致即可。
1.5 签名串编码
生成的签名串并不能直接作为请求参数,需要对其进行 URL 编码。
如上一步生成的签名串为+hLAH7Rlyoq3SSB2xUbzGpyOZn4=
,最终得到的签名串请求参数(signature)为 %2bhLAH7Rlyoq3SSB2xUbzGpyOZn4%3d
, 它将用于生成最终的请求 URL。
提示
-
如果用户的请求方法是 GET,或者请求方法为 POST 同时 Content-Type 为 application/x-www-form-urlencoded,则发送请求时所有请求参数的值均需要做 URL 编码,参数键和=符号不需要编码。非 ASCII 字符在 URL 编码前需要先以 UTF-8 进行编码。
-
有些编程语言的 http 库会自动为所有参数进行 urlencode,在这种情况下,就不需要对签名串进行 URL 编码了,否则两次 URL 编码会导致签名失败。
-
其他参数值也需要进行编码,编码采用 RFC 3986。使用 %XY 对特殊字符例如汉字进行百分比编码,其中“X”和“Y”为十六进制字符(0-9 和大写字母 A-F),使用小写将引发错误。
1.6 生成api链接示例
以getorderexpiretime接口为例,最终输出api链接为:
https://dev.kdlapi.com/api/getorderexpiretime?
sign_type=hmacsha1&orderid=954763036233510×tamp=1555080775&signature=%2bhLAH7Rlyoq3SSB2xUbzGpyOZn4%3d
注意
由于示例中的密钥是虚构的,时间戳也不是系统当前时间。为了得到一个可以正常返回的 url ,需要修改示例中的 orderid 和 apikey 为真实的订单号和密钥,并使用系统当前时间戳作为 timestamp 。
在实际调用 API 时,推荐使用配套的SDK,SDK 封装了签名的过程,开发时只关注产品提供的具体接口即可。详细信息参见 SDK中心。
2. 代码示例
提示
- 在下面的示例中,不同编程语言,甚至同一语言每次执行得到的 url 可能都有所不同,表现为参数的顺序不同,但这并不影响正确性。只要所有参数都在,且签名计算正确即可。
- 其他语言示例请参考 代码样例-数字签名 (sdk_hmacsha1)
Python示例
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import time
import base64
import hashlib
import hmac
import requests
class Auth:
"""用于保存用户orderid、apiKey,以及计算签名的对象。"""
def __init__(self, orderId, apiKey):
self._orderId = orderId
self._apiKey = apiKey
@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.apiKey.encode('utf8'), raw_str.encode('utf8'), method).digest()
except UnicodeDecodeError as e:
hmac_str = hmac.new(self.apiKey.encode('utf8'), raw_str, method).digest()
return base64.b64encode(hmac_str)
@property
def orderId(self):
return self._orderId
@property
def apiKey(self):
return self._apiKey
def _get_base_res(method, endpoint, params):
"""处理基础请求,
若响应为json格式则返回请求结果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: # 返回结果不是json格式, 直接返回
return r.content.decode('utf8')
except Exception as e:
print(str(e))
if __name__ == '__main__':
orderid = '9266892014xxxxx'
api_key = 'jd1gzm6ant2u7pojhbtl0bam0xpzsm1c'
method = 'GET' # 请求方式
endpoint = 'dps.kdlapi.com/api/getdpsvalidtime'
# 除signature外的所有参数都放入params
params = {
'orderid': orderid,
'sign_type': 'hmacsha1',
'timestamp': int(time.time()),
'proxy': '27.42.139.229:2057',
}
auth = Auth(orderid, api_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封装了签名计算过程,让您免去了这部分的编程工作,配置好apikey即可调用。