Sugar BI中的大屏和报表页面都可以公开分享,公开分享是指对所有的互联网用户开放,用户不需要使用Sugar BI的账号登录,直接通过您公开分享的 url 链接地址就能在浏览器上直接访问您开发的Sugar BI可视化页面,并且没有任何的权限管理,所有用户都可以访问(当然,您也可以对公开分享的页面设置访问密码,将在下面的文档中详细说明)。
下面将描述如何对大屏页面进行公开分享,报表页面的公开分享操作也同样类似。
大屏公开分享
在空间管理中心的「大屏管理」中,就可以如下图操作栏中有「公开分享」的按钮
如上图,公开分享有三种模式:
- 公开分享:即所有互联网用户都能随意访问
- 加密公开分享:即用户在访问发布的大屏链接时需要输入密码进行验证,验证通过之后才能访问,否则不能访问;并且为了方便您将发布的大屏使用 iframe 的方式嵌入到自己的系统中,我们还允许您设置 iframe 免密域名,当大屏作为 iframe 嵌入这些域下的网页时,可以跳过密码验证,其他情况仍需要密码验证。
- 通过 Token 验证:即用户在访问发布的大屏链接时需要通过 Sugar BI 提供的 Token 参数签名计算生成访问 URL,用此 URL 访问时系统会自动进行访问 URL 的 Token 验证,验证通过之后才能访问大屏链接,否则不能访问,以此来将大屏的访问权限与您的权限体系进行集成。
此外,还可以设置分享页面的语言环境为中文或英文。
通过 Token 验证使用流程
按上图设置分享:
- 选择通过 Token 验证选项
- 记录输入框中生成的 Token 验证码
- 勾选验证有效期(可选),自定义调整验证有效期时长,最短 1 小时,最长 32 小时,如果不勾选验证有效期,页面有效期默认为 1 分钟。有效期是指根据 Token 生成的签名参数的有效期,例如您复制生成的最终公开分享的 URL 地址,如果有效期是默认的 1 分钟,那么您复制的 URL 地址在 1 分钟之后就会过期,页面也将不能访问,这时只有通过重新计算签名参数来生成新的 URL 地址才能访问,这样就充分保证了您页面的安全性
设置 Token 验证分享成功后,再次打开报表的分享页面,页面提示 Token 认证失败,表示您的访问被拒绝了。 如果想要打开分享页面,需要完成以下步骤:
- 使用上一步生成的分享链接,记录链接中 URL 的最后一段(分享编码)
- 将上一步记录的分享编码与当前时间(毫秒)使用|(竖线)连接
- 使用 Token 通过
HMAC-SHA256 base64
算法,对上一步得到的 Token 验证码进行加密 - 将时间和加密后的签名分别命名为
_sugar_time
,_sugar_signature
- 将以上参数放入 URL 的 querystring 中
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');
let token = 'OAMf7CvniOGgoNijH9mFHEHSAf7****';
let shareID = '1827981ec07ac66f937a88c9e65f****'; // shareID详见前面文档中的说明
let time = Date.now();
let stringToSign = shareID + '|' + time;
let signature = crypto.createHmac('sha256', token).update(stringToSign).digest().toString('base64');
// url需要根据实际情况相应修改
let url =
'https://sugar.baidubce.com/dashboard/' +
shareID +
'?_sugar_time=' +
time +
'&_sugar_signature=' +
encodeURIComponent(signature);
PHP
<?php
$token = "OAMf7CvniOGgoNijH9mFHEHSAf7****";
$shareID = "1827981ec07ac66f937a88c9e65f****"; // shareID详见前面文档中的说明
$time = time()*1000;
$stringToSign = $shareID.'|'.$time;
$signature = urlencode(base64_encode(hash_hmac('sha256', $stringToSign, $token, true)));
// url需要根据实际情况相应修改
$url = "https://sugar.baidubce.com/dashboard/".$shareID."?_sugar_time=".$time."&_sugar_signature=".$signature;
?>
<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){
Date date = new Date();
Long time = date.getTime();
String stringToSign = shareID + "|" + time;
String signature = HMACSHA256(stringToSign.getBytes(), token.getBytes());
// url需要根据实际情况相应修改
String url = "https://sugar.baidubce.com/dashboard/"+ shareID +"?_sugar_time="+time+"&_sugar_signature="+ signature;
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 {
System.out.println(getSignedUrl("shareID***", "token***")); // 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)
{
// url需要根据实际情况相应修改, shareID详见前面文档中的说明
Console.WriteLine(GenerateUrl("https://sugar.baidubce.com/dashboard/", "1827981ec07ac66f937a88c9e65f****", "OAMf7CvniOGgoNijH9mFHEHSAf7****"));
}
private static string GenerateUrl(string sugarBase, string shareID, string token, Dictionary<string, string> customeParams)
{
string timestamp = GetTimeStamp();
string signStr = shareID + "|" + timestamp;
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);
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 中参数使用 Token 验证
如果您的大屏 URL 中需要传递参数,例如:员工编号,为了安全性,建议您使用 Sugar BI 提供的 Token 参数签名校验,来防止访问者通过修改页面传递的参数来访问其他未授权的页面数据,详情请参见「分享页 Token 参数签名校验」。
IP 白名单访问
开启 IP 白名单后,发布的大屏仅允许在指定的 IP 白名单范围内访问,如果您使用了非白名单 IP 访问当前大屏,将被拒绝访问。
输入的 IP 类型支持 CIDR 模式,多个 IP 可使用英文逗号分隔。
报表公开分享
空间的管理员在管理中心的「报表管理」页面中,就可以进行报表的公开分享操作,具体的操作方式和上面的「大屏的公开分享」基本一样。
自动调整高度
报表可以通过 iframe 的方式嵌入到第三方页面中,如果需要支持自动调整 iframe 的高度,请参考如下的代码:
<script>
window.addEventListener('message', function (e) {
var height = e.data.height;
document.getElementById('sugar-report').style.height = height + 'px';
});
</script>
<iframe src="{分享 url}" style="border: none;" width="960" id="sugar-report"></iframe>