上云无忧 > 文档中心 > 百度智能云数据可视化Sugar BI - 分享页Token参数签名校验
数据可视化Sugar BI
百度智能云数据可视化Sugar BI - 分享页Token参数签名校验

文档简介:
下面介绍在发布大屏和报表时,使用 Token 参数签名校验的方法。通过 Token 参数签名校验功能,您可以对大屏和报表交互时传递的参数进行签名鉴权,来防止访问者通过修改页面传递的参数来访问其他未授权的页面数据,从而提高数据以及用户信息的安全性。
*此产品及展示信息均由百度智能云官方提供。免费试用 咨询热线:400-826-7010,为您提供专业的售前咨询,让您快速了解云产品,助您轻松上云! 微信咨询
  免费试用、价格特惠

下面介绍在发布大屏和报表时,使用 Token 参数签名校验的方法。通过 Token 参数签名校验功能,您可以对大屏和报表交互时传递的参数进行签名鉴权,来防止访问者通过修改页面传递的参数来访问其他未授权的页面数据,从而提高数据以及用户信息的安全性。

前提条件

在使用 Token 参数签名校验前,请确保:

  • 大屏或报表使用 Token 验证的方式进行公开分享,具体请参见「公开和加密分享」。
  • 大屏在 URL 地址中传递参数(直接在 URL 后面加参数)。
  • 大屏 URL 中传递的参数要求不能被篡改。

背景信息

例如:

某用户的系统嵌入了 Sugar BI 大屏,URL 地址通过 Token 计算出来,并且在 URL 地址中传递area(地区)参数给大屏以展示相对应地区的数据,可以使用 https://sugar.baidubce.com/dashboard/1827981ec07ac66f937a88c9e65f****?_sugar_time=1612959542484&_sugar_signature=H09EX3nMls%2FE6IzhZKr6U6LfNq2Xl%2FJK%2BxYWoPv65D****&area=华东 来访问大屏。

其中 area(地区)是为大屏传递的参数,存在被篡改的可能。比如华东的员工将 URL 改成 https://sugar.baidubce.com/dashboard/1827981ec07ac66f937a88c9e65f****?_sugar_time=1612959542484&_sugar_signature=H09EX3nMls%2FE6IzhZKr6U6LfNq2Xl%2FJK%2BxYWoPv65D****&area=华北 ,就可以看到华北的数据。因此,为了保证数据的安全,需要对用户传递的参数进行签名鉴权,保证计算得到的 URL 参数不能被更改,如果私自更改了传参,页面将无法访问。

签名参数规则

  • 需要加入签名的参数,其参数名需以 sugar_sign_ 开头,后面可以带任何有效的参数名字符
  • 不符合此签名参数规则的参数,将不会进行参数签名校验,允许修改参数值
  • 签名参数按升序排序

使用流程

  1. 确定需要签名计算的参数名(即不允许被篡改的参数)
  2. 在大屏或报表开发完成后,使用 Token 验证的方式发布大屏或报表
  3. 使用带签名参数的 URL 计算生成访问大屏或报表的 URL
  4. 使用上一步中计算得到的 URL 访问大屏或报表,在访问过程中,系统会自动进行参数签名校验
  5. 如果参数签名校验功能正常,当访问者修改了签名参数,再次访问此 URL 时,访问会被拒绝

带签名参数的 URL 计算

shareID 说明

shareID 是大屏/报表在分享时自动生成的 url 中的部分,下面对大屏和报表中分别说明:

大屏分享的 url 地址如:https://sugar.aipage.com/dashboard/41510e632e1e1e4767b0a041030670ec,41510e632e1e1e4767b0a041030670ec 就是 shareID

报表分享的 url 地址如:https://sugar.aipage.com/report/r_1013e-8xdmi3ud-k9wl5p/06e84b7f924ecc9c33857e832de04127,06e84b7f924ecc9c33857e832de04127 就是 shareID

示例代码如下:

Node.js


const crypto = require('crypto'); const querystring = require('querystring'); 
const signedQueryParamReg = /^sugar_sign_.*/; // 符合此正则表达式的参数是需要签名的。
 let token = 'OAMf7CvniOGgoNijH9mFHEHSAf7****'; let shareID = '1827981ec07ac66f937a88c9e65f****';
 // shareID详见前面文档中的说明 const time = Date.now(); const customeParams = { sugar_sign_no: 
191866, name: 101 }; let signParamsStr = Object.keys(customeParams) .filter(paramName =>
 customeParams[paramName] && signedQueryParamReg.test(paramName)) .sort() .map(param => 
`${param}=${customeParams[param]}`) .join('&'); let stringToSign = [shareID, time];
 signParamsStr && stringToSign.push(signParamsStr); stringToSign = stringToSign.join('|'); 
let signature = crypto.createHmac('sha256', token).update(stringToSign).digest().toString('base64');
 let queryParams = { _sugar_time: time, _sugar_signature: signature }; Object.keys(customeParams).
forEach(paramName => { queryParams[paramName] = customeParams[paramName]; });
 let url = `https://sugar.baidubce.com/dashboard/${shareID}?${querystring.stringify(queryParams)}`; console.log(url);


PHP


<?php
  $token = "OAMf7CvniOGgoNijH9mFHEHSAf7****"; $shareID = "1827981ec07ac66f937a88c9e65f****"; 
// shareID详见前面文档中的说明 $time = time()*1000; $customeParams = array( 'sugar_sign_no'=>'191866', 
'name'=>'101' ); $sign_array = preg_grep("/^sugar_sign_.*/", array_keys($customeParams)); sort($sign_array); 
function toPlain($v) { global $customeParams; return "$v=$customeParams[$v]"; }; $signParamsStr
 = join("&",array_map("toPlain",$sign_array)); $stringToSign = $shareID.'|'.$time.'|'.$signParamsStr;
 $signature = urlencode(base64_encode(hash_hmac('sha256', $stringToSign, $token, true))); 
$queryParams = join("&",array_map("toPlain",array_keys($customeParams))); $url = "https:
//sugar.baidubce.com/dashboard/".$shareID."?_sugar_time=".$time."&_sugar_signature=".$signature."&".
$queryParams; echo $url; ?> <iframe width=100% height=100% src="<?=$url?>"/>


Java

package com.company; import java.security.*; import java.util.Date; import javax.crypto.*; 
import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; import 
java.net.URLEncoder; public class TokenTest { public static String getSignedUrl(String shareID, 
String token, String signParamsStr) { Date date = new Date(); Long time = date.getTime(); String
 stringToSign = shareID + "|" + time; if (!StringUtils.isEmpty(signParamsStr)) { stringToSign
 = stringToSign + "|" + signParamsStr; } String signature = HMACSHA256(stringToSign.getBytes(), 
token.getBytes()); String url = "https://sugar.baidubce.com/dashboard/" + shareID + "?_sugar_time=" 
+ time + "&_sugar_signature=" + signature + "&" + signParamsStr; return url; } /**
    *  使用java原生的摘要实现SHA256加密。
    * @param str加密后的报文。
    * @return
    */ public static 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))); } catch (NoSuchAlgorithmException e) 
{ e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } return null; 
} private static String byte2Base64(byte[] bytes){ return Base64.encodeBase64String(bytes); 
} public static void main(String[] args) throws Exception { String signedQueryParamReg = "^sugar_sign_.*";
 Map<String, Integer> customeParams = new HashMap<>(); customeParams.put("sugar_sign_no", 191866);
 customeParams.put("name", 101); String signParamsStr = customeParams.entrySet().stream().filter(entry -> 
Pattern.matches(signedQueryParamReg, entry.getKey())) .map(entry -> entry.getKey() + "=" +
 entry.getValue()) .sorted() .collect(Collectors.joining("&")); System.out.println(getSignedUrl
("shareID", "token", signParamsStr)); // shareID详见前面文档中的说明 } }

.NET

using System; using System.Security.Cryptography; using System.Text.RegularExpressions;
 using System.Collections.Generic; using System.Linq; using System.Web; using System.Text; namespace sugarToken 
{ class Program { static void Main(string[] args) { var dic = new Dictionary<string, string>();
 // 自定义参数。 dic.Add("sugar_sign_no", "191866"); // sugar_sign_开头,需要签名。 dic.Add("sugar_sign_lo",
 "mm"); dic.Add("sugar_sign_mo", "aa"); dic.Add("name", "101"); // 不需要签名。 // 分享页前缀,
大屏分享shareID、token,自定义参数字典。 Console.WriteLine(GenerateUrl("https://sugar.baidubce.com/dashboard/",
 "1827981ec07ac66f937a88c9e65f****", "OAMf7CvniOGgoNijH9mFHEHSAf7****", dic)); } private static 
string GenerateUrl(string sugarBase, string shareID, string token, Dictionary<string, string> customeParams) 
{ string pattern = @"^sugar_sign_.*"; string timestamp = GetTimeStamp(); // 参数排序 Dictionary<string,
 string>.KeyCollection keyCol = customeParams.Keys; List<string> signKeys = new List<string>(); foreach
 (var item in keyCol.ToList()) { if (Regex.IsMatch(item, pattern)) { signKeys.Add(item); } } 
// 按照key排序 signKeys = signKeys.OrderBy(k => k).ToList(); string paramsSignStr = signKeys.Aggregate("", 
(total, key) => { if (total != "") { total += "&"; } total += key + "=" + customeParams[key]; return total; }); 
string signStr = shareID + "|" + timestamp + "|" + paramsSignStr; var encoding = new System.
Text.ASCIIEncoding(); byte[] keyByte = encoding.GetBytes(token); byte[] messageBytes = encoding.GetBytes
(signStr); string signature; using (var hmacsha256 = new HMACSHA256(keyByte)) { byte[] hashmessage
 = hmacsha256.ComputeHash(messageBytes); signature = Convert.ToBase64String(hashmessage); } var paramDic 
= new Dictionary<string, string>(); paramDic.Add("_sugar_time", timestamp); paramDic.Add("_sugar_
signature", signature); foreach (var item in customeParams) { paramDic.Add(item.Key, item.Value); } 
return sugarBase + shareID + "?" + ParseToString(paramDic); } public static string GetTimeStamp()
 { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.
TotalMilliseconds).ToString(); } static public string ParseToString(IDictionary<string, string> parameters)
 { IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
 IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator(); StringBuilder query
 = new StringBuilder(""); while (dem.MoveNext()) { string key = dem.Current.Key; string value = 
dem.Current.Value; if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) { query.Append(key).
Append("=").Append(HttpUtility.UrlEncode(value)).Append("&"); } } string content = query.ToString()
.Substring(0, query.Length - 1); return content; } } }

使用以上代码示例得到的 URL 为:https://sugar.baidubce.com/dashboard/1827981ec07ac66f937a88c9e65f****?_sugar_time=1612500688339&_sugar_signature=xM%2FNQv%2F5Je7o4j2046I0Gi%2BDmQegGn%2FEHXU%2BNskcEg****&sugar_sign_no=191866&name=101,在 URL 的有效期内,如果修改了 sugar_sign_no 字段的值,链接将无法访问,如果修改了 name 字段的值,链接仍然可以访问,因为 sugar_sign_no 符合签名参数规则,参与了签名计算,而 name 不符合签名参数规则,不会进行签名计算。

带签名参数的 URL 计算工具

Sugar BI 提供了单独的签名 URL 计算工具,您可以访问「签名 URL 计算工具」来生成带签名参数的 URL 示例。

相似文档
  • Sugar BI支持将已公开分享的多个「大屏」或「报表」放入一个轮播页面中进行展示。 空间管理员可以通过空间左侧边栏中的管理中心进入轮播管理: 添加和编辑轮播页: 你可以添加和更改已有轮播页的内容,点击上图中页面右上角的按钮可以添加新的轮播。
  • 为了方便将大屏和报表页面在电脑上全屏展现,Sugar BI提供了桌面客户端程序。 下载地址是: Mac、 Windows。 下载后双击启动,首次打开需要输入大屏或报表的地址: 下次打开的时候就会自动使用这个地址全屏打开页面。
  • Sugar BI 支持移动端浏览器添加到主屏幕,再次打开后会进入全屏模式,方便每天在手机上查看大屏和报表。 iOS: iOS 的 Safari 下点击下方中间的按钮,找到「添加到主屏幕」,如下图所示:
  • 报表和大屏页面支持定时发送邮件,这样不需要每天登录 Sugar BI 就能查看报表和大屏数据。 创建定时邮件: 在报表页面点击右上角的邮箱小图标: 点击之后将会弹出定时邮件设置面板。
  • 数据预警的主要功能是帮我们监测数据中值的变化。当数据中有满足条件的值时就会发出警报。 数据预警: 数据预警支持多种图表,并且只有数据绑定方式为「数据模型」时才能进行数据预警设置(SQL 建模和 API 方式绑定图表数据的不支持)。
官方微信
联系客服
400-826-7010
7x24小时客服热线
分享
  • QQ好友
  • QQ空间
  • 微信
  • 微博
返回顶部