搜索本产品文档关键词
AIOT云云推送鉴权
所有文档
menu
没有找到结果,请重新输入

度家-AIOT语音语义平台

AIOT云云推送鉴权

AIOT云云推送鉴权

概述

在整体服务接入后,若需要对设备交互过程进行干预,则需要进云云对接,百度侧将设备交互的消息载荷按照特定协议推送到目标服务,目标服务处理后返回,后续将下发给用户设备。

API签名认证机制

客户端建立连接时,需要在 header 传递 Timestamp, AccessKey, Authorization 参数。

名词 描述
Timestamp 系统时间戳(示例中时间需要在5分钟内,否则为失效)
ACCESS_KEY 百度侧提供访问key
SECRET_KEY 百度侧提供密钥key
RequestBody 请求体实际载荷
Authorization Authorization参数签名过程:整个签名摘要使用HMAC-SHA256算法,将ACCESS_KEY + Timestamp + RequestBody 进行摘要计算并且进行Base64编码,点击下载完整示例代码

接口说明

1. 通信协议

数据交换格式为JSON,所有request/response body内容均采用UTF-8编码。

请求参数包括如下4种:

参数类型 说明
URI 通常用于指明操作实体,如:POST /v1/api/foo
Query参数 URL中携带的请求参数,通常用来指明要对实体进行的动作
HEADER 通过HTTP头域传入,Timestamp, AccessKey, Authorization
RequestBody 通过JSON格式组织的请求数据体

2. 请求参数

与 ASR 结果回调接口的参数一致

Header 参数

参数 类型 说明
Content-Type string application/json
Timestamp long 时间戳(毫秒)
AccessKey string access_key
Authorization string 摘要信息

Body 参数

参数 类型 说明
logld string 日志 ID
device obj 百度三元组数据
device.fc string
device.pk string
device.ak string
query string ASR 识别结果
nlulnfos string 请求语义
extlnfo obj 扩展信息
custom string 端上自定义信息

nluInfos 字段说明 //这里只是示例

 [{\"domain\":\"clean_bot\",\"intent\":\"start_clean\",\"slots\":{\"location\":[{\"slot_type\":\"STRING\",\"text\":\"卧室\",\"value\":\"卧室\"}]}}]

extInfo 字段说明 //这里只是示例

{
  "memberId": 123456789, // 用户ID
}

3. 响应参数

logId string 日志 ID
errcode int 错误码,0为成功,其他为失败
errmsg string 错误信息
tts obj 播报信息
nlulnfos string 响应语义
ctrlparams obj 控制参数
custom string 客户自定义,透传到端上

tts 内容字段说明:

{
    "flag": 0, // 0: 正常播报(默认),1:tts 不进行播报(content字段内容不生效)
    "content":"tts text" // 用于tts播报的内容, 如果content为空,则会用百度侧的content进行播报
}

ctrlParams 字段说明:

{
  "mediaPlay": 0 // 0: 正常播报(默认),1:不进行播报
}

custom字段说明:

类型为string,百度透传结果,客户进行端云协同

原始如json数据需要序列化成 string类型

举例:

 "custom": "
   {\"otherKey1\":\"otherValue1\",\"otherKey2\":\"otherValue2\"}
". //整个内容是 string,百度透传结果,客户进行端云协同

4. 状态码

errcode 说明
0 成功
1001 鉴权失败
1002 参数错误
1003 内部错误

示例代码

实例代码块为校验签名的合法性,实际调用为百度侧进行签名,客户侧校验百度侧签名是否合法。点击下载完整示例代码

签名校验核心逻辑

{
   
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import java.security.InvalidKeyException;


/**
 * 验签工具类. 验证签名是否正确
 * 实现方需要实现以下策略
 * <p>
 * 1.时间有效性判断(建议上下5分钟之内认为有效)
 * 2.防重攻击.
 * 3.签名有效性判断
 **/
public class CloudSignature {


    /**
     * ak参数.
     */
    public static final String ACCESS_KEY = "QRtM5Mqc3Knn6duZd9xTjjfbSSlIDwln";

    /**
     * sk参数.由双方云共同拥有. 不进行网络传输.请严格保密.
     */
    public static final String SECRET_KEY = "dEtj0KZebuj6gadtg5zNdVmXBWryNUmDzbFOM7fqcKzT3Excx8lyIgsyOUPceB5nS3NlJ5LJ9TqsElx8KyC8UD3izVL0eGw5tCm44YxuV8SDPfhms5X862PtnG6MPDlf";


    /**
     * 验证签名
     *
     * @param timestamp   系统时间戳-毫秒
     * @param signature   签名
     * @param requestBody 请求内容.HTTP请求和HTTPS请求里的最原始的Body String 字符串
     * @return 是否合法
     */
    public static boolean authenticateRequest(String timestamp, String signature, String requestBody) {

        // 时间戳判断-时间有效性判断(建议上下5分钟之内认为有效)
        long now = System.currentTimeMillis();
        long currentTime = Long.parseLong(timestamp);
        // 绝对值小于5分钟之内认为有效
        long timeDiff = Math.abs(now - currentTime);
        System.out.println(timeDiff);
        if (timeDiff > 5 * 50 * 1000) {
            return false; // 时间不在5分钟之内认为无效
        }

        // 防重判断. 这里暂时不实现
        // 可以利用 requestBody 里的 logId 作为防重key


        // 签名校验
        String calculatedSignature = calculateSignature(timestamp, ACCESS_KEY, requestBody); // 根据具体算法计算请求签名
        // 如果请求签名不匹配,说明请求未经授权,拒绝鉴权
        return calculatedSignature == null || calculatedSignature.equals(signature);

        // 鉴权通过
    }

    /**
     * 计算签名
     *
     * @param timestamp   时间戳
     * @param accessKey   ak
     * @param requestBody 请求内容.是HTTP请求和HTTPS请求里的最原始的Body String 字符串
     * @return 签名
     */
    public static String calculateSignature(String timestamp, String accessKey, String requestBody) {
        try {
            // 使用HMAC-SHA256算法进行签名计算
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            String toBeSigned = accessKey + timestamp + requestBody; // 将请求内容body加入签名计算
            byte[] signatureBytes = mac.doFinal(toBeSigned.getBytes(StandardCharsets.UTF_8));
            // 将签名结果进行Base64编码
            return Base64.getEncoder().encodeToString(signatureBytes);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            e.printStackTrace();
            return null;
        }
    }

}
}

测试代码

import org.junit.Assert;
import org.junit.Test;

public class CloudSignatureTest {

    @Test
    public void normalTest() {
        // 示例使用:
        String timestamp = System.currentTimeMillis() + ""; // 获取当前时间戳
        String accessKey = CloudSignature.ACCESS_KEY; // 替换为实际的Access Key
        String requestBody = "{\"logId\":\"123\",\"device\":{\"fc\":\"fc\",\"pk\":\"pk\",\"ak\":\"000000000019\"},\"query\":\"测试query\",\"nluInfos\":\"[{\\\"domain\\\":\\\"unknown\\\",\\\"intent\\\":\\\"unknown\\\",\\\"slots\\\":{}}]\"}"; // 替换为实际的请求内容body
        String signature = CloudSignature.calculateSignature(timestamp, accessKey, requestBody); // 计算请求签名
        // 将timestamp、accessKey、requestBody和signature kJcAI4FSIFvL6nY7uhjQ6A4THy+0sPLKd6LLcR90Ozk=
        System.out.println(signature);
        Assert.assertTrue(CloudSignature.authenticateRequest(timestamp, signature, requestBody));
    }


    @Test
    public void fakerSignatureTest() {
        // 示例使用:
        String timestamp = System.currentTimeMillis() + ""; // 获取当前时间戳

        String requestBody = "{\"logId\":\"123\",\"device\":{\"fc\":\"fc\",\"pk\":\"pk\",\"ak\":\"000000000019\"},\"query\":\"测试query\",\"nluInfos\":\"[{\\\"domain\\\":\\\"unknown\\\",\\\"intent\\\":\\\"unknown\\\",\\\"slots\\\":{}}]\"}"; // 替换为实际的请求内容body

        // 异常的ak
        String signature = CloudSignature.calculateSignature(timestamp, "faker_access_key", requestBody); // 计算请求签名
        // 将timestamp、accessKey、requestBody和signature kJcAI4FSIFvL6nY7uhjQ6A4THy+0sPLKd6LLcR90Ozk=
        System.out.println(signature);
        Assert.assertFalse(CloudSignature.authenticateRequest(timestamp, signature, requestBody));
    }


    @Test
    public void InvalidTimestampSignatureTest() {
        // 示例使用:
        String timestamp = (System.currentTimeMillis() + (60 * 1000 * 20)) + ""; // 获取当前时间戳
        String accessKey = CloudSignature.ACCESS_KEY; // 替换为实际的Access Key
        String requestBody = "{\"logId\":\"123\",\"device\":{\"fc\":\"fc\",\"pk\":\"pk\",\"ak\":\"000000000019\"},\"query\":\"测试query\",\"nluInfos\":\"[{\\\"domain\\\":\\\"unknown\\\",\\\"intent\\\":\\\"unknown\\\",\\\"slots\\\":{}}]\"}"; // 替换为实际的请求内容body
        String signature = CloudSignature.calculateSignature(timestamp, accessKey, requestBody); // 计算请求签名
        // 将timestamp、accessKey、requestBody和signature kJcAI4FSIFvL6nY7uhjQ6A4THy+0sPLKd6LLcR90Ozk=
        System.out.println(signature);
        Assert.assertFalse(CloudSignature.authenticateRequest(timestamp, signature, requestBody));
    }

}
上一篇
度家设备管理API
下一篇
百度智能云鉴权Demo示例