平台对接时调用smarteye WEB SDK开发时遇到的常见问题FAQ full

发布时间: 2024-03-01 15:31:19

一、环境准备

安装平台, 下载 smarteye server

二、开发前准备

开发前需要先获取对接的身份认证信息(AppId/AppKey), 平台会通过(AppId/AppKey)认证方式来验证请求发送者的身份。
AppId和AppKey在安装后平台的运管中心中创建,如下图。

三、对接开发

1. token生成

randNum = randInt() % 900000 + 100000
sign = hmacsha256(AppKey, [AppId]+[timestamp]+[randNum])
token = base64(sv+[sign]+[AppId]+[0]+[randNum]+[timestamp]+[From])

token有效期可在运管中心中设置,login接口回复中有有效期。所有获取token的接口,都会同时告诉对方token有效期,失效前要通过刷新token接口,更新有效期。

示例(伪代码):

AppId = "31yOb7ulVXoBLYcRbmFesMu8"
AppKey = "dpFhBlov5zOLBqYJXimg6udabM9g30FDJNgt2g"
from   = "zax-A37658F19E24"
timestamp = 1686023607
randValue = 156542
sign = hmacsha256("dpFhBlov5zOLBqYJXimg6udabM9g30FDJNgt2g", "31yOb7ulVXoBLYcRbmFesMu8+1686023607+156542")
// sign: "6a85345348c66c64c1f69765bb5f9de4305f4d12f4fc5a9c2550e25750d810e2"
token = base64("sv+6a85345348c66c64c1f69765bb5f9de4305f4d12f4fc5a9c2550e25750d810e2+31yOb7ulVXoBLYcRbmFesMu8+0+156542+1686023607+zax-A37658F19E24")
// token: "c3YrNmE4NTM0NTM0OGM2NmM2NGMxZjY5NzY1YmI1ZjlkZTQzMDVmNGQxMmY0ZmM1YTljMjU1MGUyNTc1MGQ4MTBlMiszMXlPYjd1bFZYb0JMWWNSYm1GZXNNdTgrMCsxNTY1NDIrMTY4NjAyMzYwNyt6YXgtQTM3NjU4RjE5RTI0"

2. 发送请求

平台接口文档 (besovideo.com)

发送请求前, 设置Headers中的Authorization值为上述中获取的token

附录

golang示例

package main

import (
   "crypto/hmac"
   "crypto/rand"
   "crypto/sha256"
   "encoding/base64"
   "encoding/hex"
   "fmt"
   "log"
   "math/big"
   "net/http"
   "time"
)

func HmacSha256(key string, data string) string {
   mac := hmac.New(sha256.New, []byte(key))
   mac.Write([]byte(data))
   return hex.EncodeToString(mac.Sum(nil))
}

func randNumber(min int64, max int64) int64 {
   a := min
   b := max - min

   n, err := rand.Int(rand.Reader, big.NewInt(b))
   if err != nil {
      return time.Now().UnixNano()%b + a
   }

   return n.Int64() + a
}

type Token struct {
   Type      string // 类型
   Sign      string // 签名
   AppId     string //
   Reserve   int64  // 保留
   Timestamp int64  // 时间戳(单位秒)
   From      string // 请求者
   RandNum   int64  // 随机数
   appKey    string //
}

func NewToken(appId, appKey string, from string) *Token {
   t := &Token{
      Type:      "sv",
      Sign:      "",
      AppId:     appId,
      Reserve:   0,
      Timestamp: time.Now().Unix(),
      From:      from,
      RandNum:   randNumber(100000, 999999),
      appKey:    appKey,
   }

   return t
}

func (t *Token) sign() {
   data := fmt.Sprintf("%v+%v+%v", t.AppId, t.Timestamp, t.RandNum)
   t.Sign = HmacSha256(t.appKey, data)
}

func (t *Token) String() string {
   t.sign()
   data := fmt.Sprintf("%v+%v+%v+%v+%v+%v+%v", t.Type, t.Sign, t.AppId, t.Reserve, t.RandNum, t.Timestamp, t.From)

   return base64.RawURLEncoding.EncodeToString([]byte(data))
}

func (t *Token) RealTimeString() string {
   t.Timestamp = time.Now().Unix()
   t.RandNum = randNumber(100000, 999999)

   return t.String()
}

const (
   AppId  = "31yOb7ulVXoBLYcRbmFesMu8"
   AppKey = "dpFhBlov5zOLBqYJXimg6udabM9g30FDJNgt2g"
   from   = "zax-A37658F19E24"
)

// SendRequest 发送请求
func SendRequest(request *http.Request) (*http.Response, error) {
   request.Header.Set("Authorization", NewToken(AppId, AppKey, from).RealTimeString())

   return http.DefaultClient.Do(request)
}

func main() {
   token := NewToken(AppId, AppKey, from)
   log.Println(token.RealTimeString())

   request, _ := http.NewRequest(http.MethodPost, "https://domain/api", nil)
   response, _ := SendRequest(request)
   _ = response
}

java

package token_demo;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Random;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Token {
    String appId;
    String appKey;
    String type; // 类型
    String sign; // 签名
    int reserve; // 保留
    long timestamp; // 时间戳(单位秒)
    String from; // 请求者
    int randNum;// 随机数

    public Token(String appId, String appKey, String from) {
        this.appId = appId;
        this.from = from;
        this.appKey = appKey;

        this.type = "sv";
        this.reserve = 0;
        this.timestamp = System.currentTimeMillis() / 1000;
        this.randNum = new Random().nextInt(999999 - 100000) + 100000;
    }

    private void Sign() throws InvalidKeyException, NoSuchAlgorithmException {
        String data = String.format("%s+%d+%d", this.appId, this.timestamp, this.randNum);

        this.sign = this.HmacSha256(this.appKey, data);
    }

    public String String() throws InvalidKeyException, NoSuchAlgorithmException {
        this.Sign();

        String data = String.format("%s+%s+%s+%d+%d+%d+%s", this.type, this.sign, this.appId, this.reserve,
                this.randNum, this.timestamp, this.from);

        return Base64.getUrlEncoder().encodeToString(data.getBytes());
    }

    public String RealTimeString() throws InvalidKeyException, NoSuchAlgorithmException {
        this.timestamp = System.currentTimeMillis() / 1000;
        this.randNum = new Random().nextInt(999999 - 100000) + 100000;

        return this.String();
    }

    String HmacSha256(String key, String data) throws NoSuchAlgorithmException, InvalidKeyException {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);

        byte[] out = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(out);
    }

    private String bytesToHex(byte[] hash) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        String AppId = "31yOb7ulVXoBLYcRbmFesMu8";
        String AppKey = "dpFhBlov5zOLBqYJXimg6udabM9g30FDJNgt2g";
        String from = "zax-A37658F19E24";

        Token t = new Token(AppId, AppKey, from);

        for (int i = 0; i < 10; i++) {
            System.out.println(t.RealTimeString());
        }

    }
}

在Iframe中集成WebApp页面遇到的问题

  1. iframe中跨域页面无法写入cookie,导致依赖cookie传递token的接口失效;目前webapp中全部接口已经在url中携带token。参考MDN Cookie Security
  2. iframe中访问麦克风需要向iframe标签添加allow属性,否则iframe中页面无法访问。
    语法:
    Permissions-Policy:<directive> <allowlist>
    allow='Permissions-Policy'
    示例
    <iframe src="<https://example.com>" allow="microphone https://example.com;">
    </iframe>
    参考文档
    Deprecating Permissions in Cross-Origin Iframes
    MDN Permissions-Policy

服务器部署到线上后如何解决跨域问题

smarteye server服务器默认不支持跨域;可能需要配置下:http://wiki.besovideo.com:7788/zh/smarteye/servere/common-problem
运管中心->系统维护->参数配置: bvnginx-x 配置中添加

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Headers *;
if ($request_method = 'OPTIONS') {
  add_header Access-Control-Allow-Origin *;
  add_header Access-Control-Allow-Methods *;
  add_header Access-Control-Allow-Headers *;
  add_header 'Content-Length' 0;
  return 204;
}

 

免登录跳转地址格式

https://smarteye.besovideo.com/client/app/#/login?&user=test&password=123&device=PU_22060310
device参数用来指示跳转到对应的设备详情界面,如果不填,会跳转到登录后的首页。

  • 使用token跳转:

好处:跳转时不会泄漏密码。

http://192.168.88.11:9780/client/webapps/safeProduction/#/login?&token=2CC73DBF37BF358F809FD435DDC1EB8C&device=PU_55AA00

 

@besovideo/webrtc-player

https://www.npmjs.com/package/@besovideo/webrtc-player

webrtc调用的是浏览器的接口,参考MDN webrtc连接建立过程
其中创建offer接口就是创建SDP。

 

调用webrtc接口,调用视频播放,样式错乱,视频控件不受样式控制,div使用的是Demo里的  

解答:没有引入播放组件的css

 

多源视频融合通信可视指挥调度平台VMS/smarteye概述,https://www.besovideo.com/detail?t=1&i=240

多源视频融合平台VMS/smarteye,免费的GB28181 server, 免费的RTMP推流server,RTSP server,车载机部标JT808,JT1078服务器、标准SIP服务器, https://www.besovideo.com/detail?t=2&i=1321

全面支持国产信创系统,在linux(麒麟、统信等信创系统)服务器上安装smarteye server的操作说明, https://www.besovideo.com/detail?t=1&i=248

关于融合通信~可视指挥调度平台VMS/smarteye的说明,https://www.besovideo.com/detail?t=1&i=304