文档简介:
概述
智能外呼开放平台接口,每次调用均需进行Token认证鉴权。
使用前提
开通智能外呼产品
生成公式
认证字符串的格式:
cc-api-auth-v{version}/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds}/{signedHeaders}/{signature}。
主要包含了3部分,即前缀字符串(authStringPrefix)、签名头域(signedHeaders)和签名摘要(signature),其中: 前缀字符串:cc-api-auth-v1/{AK}/{timestamp}/{expirationPeriodInSeconds } 签名头域:即签名算法中涉及到的HTTP头域列表 签名摘要:为通过HMAC SHA256算法计算所得
编码生成步骤
创建前缀字符串
将已知参数拼接为如下形式: cc-api-auth-v1/{AK}/{timestamp}/{expirationPeriodInSeconds}
- AK 可通过在配置台 系统管理-> API配置页面获取到
- timestamp 为token 生成的时间,格式为2014-06-01T23:00:10Z表示UTC时间2014年6月1日23点0分10秒
- expirationPeriodInSeconds 签名有效期限,从timestamp所指定的时间开始计算,单位为秒。
创建规范请求(canonicalRequest),确定签名头域(signedHeaders)
CanonicalRequest的计算公式为:
CanonicalRequest = HTTP Method + "\n" + CanonicalURI + "\n" + CanonicalQueryString + "\n" + CanonicalHeaders。
HTTP Method
指HTTP协议中定义的GET、PUT、POST等请求方法,必须使用全大写的形式
GET
POST
PUT
DELETE
HEAD
CanonicalURI
CanonicalURI是对URL中的绝对路径进行编码后的结果,即CanonicalURI = UriEncodeExceptSlash(Path)。要求绝对路径Path必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”。函数UriEncodeExceptSlash的具体含义及功能请参考相关函数。
示例: 若URL为 https: //bos.cn-n1.baidubce.com/example/测试 ,则其URL的Path为/example/测试,将之规范化得到CanonicalURI =UriEncodeExceptSlash(/example/测试)= /example/%E6%B5%8B%E8%AF%95。
CanonicalQueryString
CanonicalQueryString是对于URL中的Query String(Query String即URL中“?”后面的“key1 = valve1 & key2 = valve2 ”字符串)进行编码后的结果。
编码步骤如下:
- 提取URL中的Query String项,即URL中“?”后面的“key1 = valve1 & key2 = valve2 ”字符串。
- 将Query String根据&分隔符拆开成若干项,每一项是key=value或者只有key的形式。
- 对拆开后的每一项进行编码处理,分以下三种情况。
- 当该项的key是authorization时,直接忽略该项。
- 当该项只有key时,转换公式为UriEncode(key) + "="的形式。
- 当该项是key=value的形式时,转换公式为 UriEncode(key) + "=" + UriEncode(value) 的形式。这里value可以是空字符串。
4.将每一项转换后的字符串按照字典顺序(ASCII码由小到大)排序,并使用& 符号连接起来,生成相应的CanonicalQueryString。
编码示例:
获取URL为https: //bos.cn-n1.baidubce.com/example?text&text1=测试&text10=test的CanonicalQueryString。
1.提取URL中的Query String,得到 text&text1=测试&text10=test。 2.根据&对Query String进行拆分,得到text 、text1=测试 、 text10=test三项。 3.对拆分的每一项进行编码。
- 对text项进行编码:UriEncode("text") + "=",得到"text="
- 对text1=测试项进行编码:UriEncode("text1") + "=" + UriEncode("测试"),得到"text1=%E6%B5%8B%E8%AF%95"
- 对text10=test项进行编码:UriEncode("text10") + "=" + UriEncode("test"),得到"text10=test"
4.对上面三项编码后的字符串进行(按照ASCII码由小到大)排序,得到结果是text10=test 、text1=%E6%B5%8B%E8%AF%95 、text= ,然后用&连接起来,得到CanonicalQueryString为text10=test&text1=%E6%B5%8B%E8%AF%95&text=。
CanonicalHeaders
CanonicalHeaders是对HTTP请求中的Header部分进行选择性编码的结果。 在这个步骤中,可根据Header部分确定签名头域(signedHeaders)。签名头域是指签名算法中涉及到的HTTP头域列表。HTTP头域名字一律要求小写且头域名字之间用分号(;)分隔,如host;range;x-bce-date。列表按照字典序排列。当它为空时表示系统默认取Host.
对Header进行编码获取CanonicalHeaders,编码步骤如下。
- 将Header的名字变成全小写,注意仅改名字。
- 将Header的值去掉开头和结尾的空白字符。
- 经过上一步之后值为空字符串的Header忽略,其余的转换为 UriEncodeExceptSlash(name) + ":" + UriEncodeExceptSlash(value) 的形式。 把上面转换后的所有字符串按照字典序进行排序。
- 将排序后的字符串按顺序用\n符号连接起来得到最终的CanonicalHeaders。
Host: bj.bcebos.com
Date: Mon, 27 Apr 2015 16:23:49 +0800 Content-Type: text/plain
Content-Length: 8 Content-Md5: NFzcPqhviddjRNnSOGo4rw== x-bce-date:
2015-04-27T08:23:49Z
- 选择需要编码的Header,然后把所有名字都改为小写。
host: bj.bcebos.com
date: Mon, 27 Apr 2015 16:23:49 +0800 content-type: text/plain
content-length: 8 content-md5: NFzcPqhviddjRNnSOGo4rw==
- 将Header的值去掉开头和结尾的空白字符。
host:bj.bcebos.com
date:Mon, 27 Apr 2015 16:23:49 +0800 content-type:text/plain
content-length:8 content-md5:NFzcPqhviddjRNnSOGo4rw==
3.对每个Header进行UriEncodeExceptSlash转换。
host:bj.bcebos.com
date:Mon%2C%2027%20Apr%202015%2016%3A23%3A49%20%2B0800
content-type:text/plain
content-length:8 content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D?
4.将步骤3中转换后的所有字符串按照字典序进行排序。
content-length:8 content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D?
content-type:text/plain
date:Mon%2C%2027%20Apr%202015%2016%3A23%3A49%20%2B0800
host:bj.bcebos.com
5.将排序后的字符串按顺序用\n符号连接起来得到最终结果。
content-length:8 content-md5:NFzcPqhviddjRNnSOGo4rw%3D%3D?
content-type:text/plain
date:Mon%2C%2027%20Apr%202015%2016%3A23%3A49%20%2B0800
host:bj.bcebos.com
同时获得认证字符串的signedHeaders内容应该是content-length;content-md5;content-type;date;host
生成派生密钥(signingKey)
SigningKey = HMAC-SHA256-HEX(sk, authStringPrefix)
其中:
- HMAC-SHA256-HEX是HMAC SHA256算法函数
- sk为生成信息摘要时所使用的密钥,即用户的Secret Access Key,可通过在配置台 系统管理-> API配置页面获取到
- authStringPrefix,进行哈希运算的消息,代表认证字符串的前缀部分,即:cc-api-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds}。
生成签名摘要及认证字符串(authorization)
通过上面的计算得到的SigningKey和CanonicalRequest按照下面公式可以得到签名。
Signature = HMAC-SHA256-HEX(SigningKey, CanonicalRequest)
最后由公式cc-api-auth-v1/{accessKeyId}/{timestamp}/{expirationPeriodInSeconds }/{signedHeaders}/{signature}得到认证字符串。
相关函数说明
HMAC-SHA256-HEX()
调用HMAC SHA256算法,根据开发者提供的密钥(key)和密文(message)输出密文摘要,并把结果转换为小写形式的十六进制字符串。
Lowercase()
将字符串全部变成小写。
Trim()
去掉字符串开头和结尾的空白字符。
UriEncode()
RFC 3986规定,"URI非保留字符"包括以下字符:字母(A-Z,a-z)、数字(0-9)、连字号(-)、点号(.)、下划线(_)、波浪线(~),算法实现如下:
- 将字符串转换成UTF-8编码的字节流
- 保留所有“URI非保留字符”原样不变
- 对其余字节做一次RFC 3986中规定的百分号编码(Percent-encoding),即一个“%”后面跟着两个表示该字节值的十六进制字母,字母一律采用大写形式。
UriEncodeExceptSlash()
与UriEncode() 类似,区别是斜杠(/)不做编码。一个简单的实现方式是先调用UriEncode(),然后把结果中所有的%2F都替换为/ UriEncode()函数参考代码如下:
public static String uri-encode(CharSequence input, boolean encodeSlash)
{ StringBuilder result = new StringBuilder(); for (int i = 0; i < input.length();
i++) { char ch = input.charAt(i); if ((ch >= 'A' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch ==
'_' || ch == '-' || ch == '~' || ch == '.') { result.append(ch);
} else if (ch == '/') { result.append(encodeSlash ? "%2F" : ch);
} else { result.append(toHexUTF8(ch)); } } return result.toString(); }
代码示例
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import hashlib import hmac import urllib import time # 1.AK/SK、host、method、URL绝对路径、querystring AK =
"07b2391cee0f40bd806c6318a572b3ef" SK = "83195d93149b4692821
cfb424482b961" host = "localhost:8080" # 接口的域名,或者ip端口 method = "POST" query = "" # 通过url param传参时,将参数填这 URI
= "/api/test" # 接口path # 2.x-bce-date x_bce_date = time.gmtime() x_bce_date = time.strftime
('%Y-%m-%dT%H:%M:%SZ',x_bce_date) # 3.header和signedHeaders header = { "Host":host, } signedHeaders = "Host" # 4.认证字符串前缀 authStringPrefix = "cc-api-auth-v1" + "/" +AK + "/" +x_bce_date +
"/" +"1800" print("authStringPrefix=" + authStringPrefix) # 5.生成CanonicalRequest #5.1生成CanonicalURI CanonicalURI = urllib.quote(URI) # windows下为urllib.parse.quote,
Linux下为urllib.quote #5.2生成CanonicalQueryString CanonicalQueryString = query
# 如果您调用的接口的query比较复杂的话,需要做额外处理 #5.3生成CanonicalHeaders result = [] for key,value in header.items(): tempStr =
str(urllib.quote(key.lower(),safe="")) + ":" + str(urllib.
quote(value,safe="")) result.append(tempStr) result.sort()
CanonicalHeaders = "\n".join(result) #5.4拼接得到CanonicalRequest CanonicalRequest = method + "\n" + CanonicalURI + "\n" +
CanonicalQueryString +"\n" + CanonicalHeaders print("CanonicalRequest="
+ CanonicalRequest) # 6.生成signingKey signingKey = hmac.new(SK.encode('utf-8'),authStringPrefix.encode
('utf-8'),hashlib.sha256) print("signingKey=" + signingKey.hexdigest
)) # 7.生成Signature Signature = hmac.new((signingKey.hexdigest()).encode('utf-8'),
CanonicalRequest.encode('utf-8'),hashlib.sha256) print("Signature="
+ Signature.hexdigest()) # 8.生成Authorization并放到header里 header['Authorization'] = authStringPrefix + "/" +signedHeaders
+ "/" +Signature.hexdigest() print("token=" + authStringPrefix +
"/" +signedHeaders + "/" +Signature.hexdigest()) # 9.发送API请求并接受响应 #import requests #import json #body={ # "name" : "QQQQQQ" # } #url = "http://"+host + URI #r
= requests.put(url,headers = header,data=json.dumps(body)) #print(r.text)
java SDK使用示例
平台提供Token认证的java sdk,支持开发者直接调用获取Token。
sdk jar包地址:https://bce-doc-on.bj.bcebos.com/bce-documentation/CCC/cf-auth-api-token-5.1.5-SNAPSHOT-jar-with-dependencies.jar
Maven POM文件 引入SDK jar包
<dependencies> <dependency> <groupId>com.baidu.contact-center</groupId>
<artifactId>cf-auth-api-token</artifactId> <version>5.1.5-SNAPSHOT<
/version> <scope>system</scope> <systemPath>/Users/lihuiyao01/Desktop
/cf-auth-api-token-5.1.5-SNAPSHOT-jar-with-dependencies.jar</sys
temPath> </dependency> </dependencies>
SDK 示例代码
public class TokenGenerate { public static void main(String[] args)
{ ApiTokenV1.ApiAuthTokenV1Builder builder = new ApiTokenV1.
ApiAuthTokenV1Builder(); // 必填参数 ak,sk,uri,host,http method,
过期时间 builder.ak("ac92a217bb4f43ebbfe31cda859f647e"); //
ak builder.sk("c5432f291e2d472395348d399a8d8640"); //
sk builder.uri("/api/v1/robot/list"); // 接口路径 builder.host
("aicc.bce.baidu.com"); // host builder.httpMethod("GET");
// http method builder.expireInSeconds(1800); // 过期时间
// 以下是非必须参数 // 参与生成token的请求头, 此处若使用了x-bce-date,
则调用外呼api接口时,请求头内必需带上x-bce-date HashMap<String, String>
headerMap = new HashMap<String, String>(); headerMap.put("x-bce-date",
"2021-10-12T10:02:14Z"); builder.httpHeaderMap(headerMap); // builder.
httpHeader("Content-Type", "application/json"); // url里?带的参数,
如/api/v1/robot/list?robotName=test, 没有?参数可以不调用此方法
builder.queryStr("robotName=test&pn=1"); System.out.println(builder.
build().getToken()); } }