
# 华为云Astro大屏应用分享页Token签名校验使用说明
通过Token参数签名校验功能，可以对大屏交互时传递的URL进行签名鉴权，保证大屏的URL访问链接不会被篡改，从而提高大屏数据以及用户信息的安全性。
#### 前提条件
在使用Token签名验证功能前，需满足以下条件：
- 华为云Astro大屏应用大屏页面，使用Token验证的方式进行发布。
- 华为云Astro大屏应用大屏页面，以Get的方式在URL中传递参数，且必须带有_dmax_signature、_dmax_time参数。
- 华为云Astro大屏应用大屏URL未被篡改。
 
#### 背景信息
用户开启了Token签名验证功能，系统返回用以生成签名的Token（用于生成签名的token不可公开），例如token=j5TZLK1DQ\*\*\*\*\*Ntquo/ErqonR0=。
假设，某用户系统嵌入了华为云Astro大屏应用大屏页面，通过Token计算签名，最终得到的分享页面链接为（如果对该分享链接进行了篡改，那么页面将无法访问）：
```
https://7a307******22a2a.canvas.cn-north-4.hwastro.cn/magno/render/share/1948907d2cb-******-3d2bcf7478fe?_dmax_time=1669621495545&name=cloud&age=36&dept=cloud&_dmax_signature=DVX7Qy******o5rs%3D
```
其中：
- _dmax_time=1669621495545：为华为云Astro大屏应用页面用户分享链接生成时间戳。如果开启了有效期设置，_dmax_time值要小于有效期值，单位为毫秒时间戳。
- _dmax_signature=DVX7Qy\*\*\*\*\*\*o5rs%3D：为Token对URL进行计算得出的签名，用于身份验证。
- name=cloud\&age=36\&dept=cloud：为用户自定义扩展参数。
 
#### 分享URL签名说明
Token签名校验，是针对整个URL计算并得出的签名。其中，"_dmax_time"为签名生成时的时间戳（该参数值可自定义，默认为计算签名时的时间）。"_dmax_signature"为最终对URL进行计算得出的签名。
![](https://support.huaweicloud.com/usermanual-astrocanvas/public_sys-resources/note_3.0-zh-cn.png)
在计算签名时，会对参数按照key升序排序，且将多个相同key的参数值进行合并。
例如，用于计算签名的URL输入如下：
```
https://7a307******22a2a.canvas.cn-north-4.hwastro.cn/magno/render/share/1948907d2cb-******-3d2bcf7478fe?_dmax_time=1669621495545&name=cloud&age=35&dept=cloud&age=36
```
则通过对参数排序，相同参数合并后（例如age），得到的用于计算的URL为：
```
https://7a307******22a2a.canvas.cn-north-4.hwastro.cn/magno/render/share/1948907d2cb-******-3d2bcf7478fe?_dmax_time=1669621495545&age=35,36&dept=cloud&name=cloud
```
#### URL签名计算代码示例
以Java代码为例，URL签名计算代码示例如下：
```
private String getSignature(String uri, TreeMap<String, String[]> parameterMap, String token) {
        List<String> parameterList = parameterMap.entrySet()
            .stream()
            .map(entry -> entry.getKey() + "=" + String.join(",", entry.getValue()))
            .collect(Collectors.toList()); // 对参数进行排序
        String sortParams = String.join("&", parameterList); // 重新拼接参数
        String usedSigUrl = String.join("?", new String[] {uri, sortParams});
        String signature = Objects.requireNonNull(
            HMACSHA256(usedSigUrl.getBytes(StandardCharsets.UTF_8), token.getBytes(StandardCharsets.UTF_8)));
        return signature;
    }
    private String HMACSHA256(byte[] data, byte[] key) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA256");
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(signingKey);
            return URLEncoder.encode(byte2Base64(mac.doFinal(data)), StandardCharsets.UTF_8.name());
        } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }
    private String byte2Base64(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }
    public void getSignatureUrl() {
        String cusUrl = "https://7a307******22a2a.canvas.cn-north-4.hwastro.cn/magno/render/share/1948907d2cb-******-3d2bcf7478fe?name=cloud&age=36&dept=cloud"; // 待签名计算url
        String uri = "https://7a307******22a2a.canvas.cn-north-4.hwastro.cn/magno/render/share/1948907d2cb-******-3d2bcf7478fe"; // uri
        String token = "xxxx"; // 页面分享认证token
        String timestamp = String.valueOf(new Date().getTime()); // 时间戳
        TreeMap<String, String[]> parameterMap = new TreeMap<>(); // 参数集合
        parameterMap.put("name", new String[] {"cloud"});
        parameterMap.put("age", new String[] {"36"});
        parameterMap.put("dept", new String[] {"cloud"});
        parameterMap.put("_dmax_time", new String[] {timestamp});
        String signature = getSignature(uri, parameterMap, token);
        String inputUrl = cusUrl + "&" + "_dmax_time=" + timestamp; // 将分享链接url拼接上时间戳参数
        System.out.println(String.join("&", inputUrl, "_dmax_signature=" + signature)); // 打印输出
    }
```
使用以上代码示例，得到的可访问签名的分享链接为：
```
https://7a307******22a2a.canvas.cn-north-4.hwastro.cn/magno/render/share/1948907d2cb-******-3d2bcf7478fe?name=cloud&age=36&dept=cloud&_dmax_time=1669639799495&_dmax_signature=2Lbxef1HvbIx4kd9pBjmHswAa******xlBu3o9M%3D
```
在URL有效期内，如果篡改了该URL任何一处，链接将无法访问。
