数据平台Open-API调用鉴权说明
构造签名signature
签名的过程是将请求参数串以及APP密钥根据一定签名算法生成的签名值,作为新的请求参数从而提高访问过程中的防篡改性。
| 参数 | 说明 |
|---|---|
| AccessId, SecretKey | 每一个客户端接入之前随机分配的 1. 做验证是计算使用。 2. 方便以后启用/停用任意一个api来源 |
| Date | 时间戳。服务器根据这个时间来判断生成的签名是否过期 |
| /itask/users?zone=beijing&page_size=10 | |
| signature | 一个不可逆算法,一般是sha1/md5等 |
- 其中AccessId相当于帐号,是公开的;SecretKey相当于密码,只有平台和开发者自己知道。开发者绝不能将SecretKey包含在http请求中
在header中包含签名
调用端可以在HTTP请求中增加 Authorization 的Header来包含签名(Signature)信息
Authorization字段计算的方法
Authorization = "IWOP " + AccessId + ":" + Signature
Signature = base64(HmacSha1(SecretKey,
VERB + "\n"
+ ContentType + "\n"
+ Date + "\n"
+ ""
+ CanonicalizedResource))
Authorization= "IWOP" + 空格 + AccessId + ":" + 签名SecretKey表示签名所需的密钥VERB表示HTTP 请求的Method,主要有PUT,GET,POST,HEAD,DELETE等- \n 表示换行符
Content-Type表示请求内容的类型,如"application/octet-stream",如果请求头不包含Content-Type,这该值为空- Date 表示此次操作的时间,且必须为GMT格式,如'Fri, 02 Feb 2018 10:44:35 GMT'。客户端时间与平台时间不能相关太大,
如果相差超过15分钟,平台会拒绝执行。 - CanonicalizedResource 表示用户想要访问的iwop资源
其中,VERB、Date和CanonicalizedResource不能为空;如果请求中的Date时间和平台服务器的时间差15分钟以上,平台服务器将拒绝该服务,并返回HTTP 403错误。
构建CanonicalizedResource的方法
用户发送请求中想访问的iwop目标资源被称为CanonicalizedResource。它的构建方法如下:
- 将CanonicalizedResource置成空字符串 "";
- 添加要访问的api的path部分(前面示例中的 '/itask/users')
如果请求包含了查询字符串(QueryString,也叫Http Request Parameters),那么将这些查询字符串及其请求值按照字典顺序,从小到大排列,以&为分隔符,按参数添加到CanonicalizedResource中。此时的CanonicalizedResource为:
http://api.mctech.vip/itask/users?page_size=10&zone=beijing注意生成的CanonicalizedResource中page_size与zone两参数已经按字母顺序重排了
计算签名头规则
- 签名的字符串必须为
UTF-8格式。含有中文字符的签名字符串必须先进行UTF-8编码,再与SecretKey计算最终签名。 - 签名的方法用RFC 2104中定义的HMAC-SHA1方法,其中Key为
SecretKey。 - 在http请求中Content-Type不是必须的,如果请求头中没有提供Content-Type,在签名算法的对应项中以空值('')替换,此处结尾的换行符
\n需要省略。 - 在所有非HTTP标准定义的header中,只有以 x-iwop- 开头的header,需要加入签名字符串;其他非HTTP标准header将被平台忽略(如上例中的x-iwop-name是需要加入签名字符串的)。
- 以
x-iwop-开头的header在签名验证前需要符合以下规范:- header的名字需要变成小写。
- header按字典序自小到大排序。
- 分割header name和value的冒号前后不能有空格。
- 每个header之后都有一个换行符\n,如果没有以
x-iwop-开头的header,CanonicalizedIWOPHeaders就设置为空。
签名示例
假如AccessId是'Hb18J9rjxX7ibdqw7DWv',SecretKey是'9rjxX7ibdqw7DWvfuldrfiiBnqTan9TrXUFOwNm2'
| 请求 | 签名字符串计算公式 | 签名字符串 |
|---|---|---|
| GET /itask/users?zone=beijing&page_size=10 Content-Type: text/html Accepts: aplication/json,*/* Date: Fri, 02 Feb 2018 10:44:35 GMT Host: api.mctech.vip |
Signature = base64(HmacSha1(SecretKey, VERB + '\n' + Content-Type + '\n'+ Date + '\n' + CanonicalizedIWOPHeaders + CanonicalizedResource)) |
'GET\ntext/html\nFri, 02 Feb 2018 10:44:35 GMT\n/itask/users?page_size=10&zone=beijing' |
可用以下方法计算签名(Signature):
- javascript
const CryptoJS = require('crypto-js')
let content = 'GET\ntext/html\nFri, 02 Feb 2018 10:44:35 GMT\nhttp://api.mctech.vip/itask/users?page_size=10&zone=beijing'
let secretKey = '9rjxX7ibdqw7DWvfuldrfiiBnqTan9TrXUFOwNm2'
// crypto-js 模块内部默认使用utf-8编码
let data = CryptoJS.HmacSHA1(content, secretKey)
let signature = data.toString(CryptoJS.enc.Base64)
console.log(signature)
- java
Charset utf8 = Charset.forName(CHARSET_UTF8)
String content = "GET\ntext/html\nFri, 02 Feb 2018 10:44:35 GMT\nhttp://api.mctech.vip/itask/users?page_size=10&zone=beijing"
String secretKey = "9rjxX7ibdqw7DWvfuldrfiiBnqTan9TrXUFOwNm2"
byte[] contentBytes = content.getBytes(utf8);
byte[] secretKeyBytes = secretKey.getBytes(utf8);
SecretKey signingKey = new SecretKeySpec(secretKeyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] signatureBytes = mac.doFinal(contentBytes);
String signature = new BASE64Encoder().encode(signatureBytes);
System.out.print(signature);
生成Authorization头
上面例子签名(Signature)计算结果应该为 'Jxszg5LHZwnLgI/5dQuVAQVT5Bs=',因为Authorization = 'IWOP ' + AccessId + ':' + Signature
而AccessId为'Hb18J9rjxX7ibdqw7DWv'
所以最后Authorization为 'IWOP Hb18J9rjxX7ibdqw7DWv:Jxszg5LHZwnLgI/5dQuVAQVT5Bs='
然后加上Authorization头来组成最后需要发送的消息:
GET /itask/users?zone=beijing&page_size=10
Authorization: IWOP Hb18J9rjxX7ibdqw7DWv:Jxszg5LHZwnLgI/5dQuVAQVT5Bs=
Content-Type: text/html
Date: Fri, 02 Feb 2018 10:44:35 GMT
Host: api.mctech.vip
返回结果
- 如果传入的AccessId不存在或被禁用了,返回403 Forbidden。错误码:InvalidAccessId。
- 若用户请求头中Authorization值的格式不对,返回400 Bad Request。错误码:InvalidArgument。
- IWOP所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。
- 如果签名验证的时候,头中没有传入Date或者格式不正确,返回403 Forbidden错误。错误码:AccessDenied。
- 传入请求的时间(Date)必须在服务器当前时间之后的10分钟以内,否则返回403 Forbidden。错误码:RequestTimeTooSkewed。
- 返回示例:
<?xml version="1.0" ?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<StringToSignBytes>58 69 66 6f 73 66 59 37 71 48 64 77 42 31 4d 55 4f 70 35 46 31 47 44 51 55 55 63 3d</StringToSignBytes>
<SignatureProvided>y5H7yzPsA/tP4+0tH1HHvPEwUv8=</SignatureProvided>
<StringToSign>
GET
text/html
Fri, 02 Feb 2018 10:44:35 GMT
/itask/users?`page_size`=10&`zone`=beijing
</StringToSign>
<IWOPAccessId>Hb18J9rjxX7ibdqw7DWv</IWOPAccessId>
</Error>