生成认证TokenV1(不推荐)
所有文档
menu

客悦·智能外呼平台 AIOB

生成认证TokenV1(不推荐)

产品详情立即使用

概述

智能外呼开放平台接口,每次调用均需进行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配置页面获取到

截屏2021-09-16 下午8.50.36.png

  • 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 ”字符串)进行编码后的结果。

编码步骤如下:

  1. 提取URL中的Query String项,即URL中“?”后面的“key1 = valve1 & key2 = valve2 ”字符串。
  2. 将Query String根据&分隔符拆开成若干项,每一项是key=value或者只有key的形式。
  3. 对拆开后的每一项进行编码处理,分以下三种情况。
  • 当该项的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,编码步骤如下。

  1. 将Header的名字变成全小写,注意仅改名字。
  2. 将Header的值去掉开头和结尾的空白字符。
  3. 经过上一步之后值为空字符串的Header忽略,其余的转换为 UriEncodeExceptSlash(name) + ":" + UriEncodeExceptSlash(value) 的形式。 把上面转换后的所有字符串按照字典序进行排序。
  4. 将排序后的字符串按顺序用\n符号连接起来得到最终的CanonicalHeaders。

编码示例: 如下是发送请求的Header:

    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
  1. 选择需要编码的Header,然后把所有名字都改为小写。
    host: bj.bcebos.com
    date: Mon, 27 Apr 2015 16:23:49 +0800
    content-type: text/plain
    content-length: 8
    content-md5: NFzcPqhviddjRNnSOGo4rw==
  1. 将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配置页面获取到

截屏2021-09-16 下午8.52.41.png

  • 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)、连字号(-)、点号(.)、下划线(_)、波浪线(~),算法实现如下:

  1. 将字符串转换成UTF-8编码的字节流
  2. 保留所有“URI非保留字符”原样不变
  3. 对其余字节做一次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 = "83195d93149b4692821cfb424482b961"
    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包地址:下载

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</systemPath>
        </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());
    }
    }