npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ezviz/openplatform-sdk

v1.0.0-beta.1

Published

萤石开放平台 Node.js SDK

Readme

萤石开放平台 Node.js SDK

安装

npm install @ezviz/openplatform-sdk

注意:本 SDK 依赖 Node.js 14 及以上版本。

Release Notes

1.0.0-beta.1

Release Date 2025-01-21

  • 提供设备类、非设备类、RTC操作、取流操作、资源访问五类Token的生成。

基本问题FAQ

  • Q: 生成Token的用处是什么?意味着什么?

    A: Token的中文含义是票据。它就象是一张高铁车票(非常类似)——在售票处,铁路公司在验明你的身份证,并且收到你的钱之后,颁发给你这样一个【凭证】,你可以持有这个【凭证】乘坐对应车次的高铁。 在我们业务中,SaaS业务方可以在验明终端用户的身份和权限后,颁发一个票据(Token),作为该终端后续可以访问萤石云平台资源的凭证。因此一个Token(票据),意味着SaaS业务方将自己访问萤石云平台的权限,(临时性地)授予了某个终端(或三方)。

    上一句话中,“SaaS业务自己访问萤石云平台的权限”,意味着这次授予,无法超过SaaS业务方自身访问萤石云平台的权限范围。 “临时性地”,表示授予的权限是存在有效期的,并且这个有效期不会很长。

  • Q: Token的实际用法是怎么样的?

    A: 在我们的设想中,终端(PC、移动端、设备端)向SaaS服务(云眸/云耀/融合云、三方开发者)发起申请,告知SaaS服务自己要在萤石云上做一个什么操作。SaaS服务需要检查这次操作是否符合终端的身份权限,在检查后,颁发Token对终端进行授权。 终端凭借Token(票据)来萤石云进行操作,萤石会检查——

    • Token(票据)是否伪造的。
    • Token(票据)是否过期了。
    • 这个Token来自哪个开发者(SaaS服务)
    • 这个Token授权的行为,是否与终端本次申请的操作的行为一致。(例如:终端不能拿着一个授权其操作设备A的票据,到萤石云平台来操作设备B)。
    • 颁发Token(票据)的开发者,是否具有执行此项操作的权限。

    上述检查都通过后,萤石云按终端本次的要求进行动作。

  • Q:Token是如何防止伪造的?

    A: Token是SaaS服务颁发权限的凭证,就像一张动车票一样,有很多限制。终端在获得Token(票据)后,有可能试图修改和伪造Token来萤石云操作。如果这种行为能够得逞,那么整套机制也就没有存在的价值了。因此Token必须有防伪机制,在铁路系统中,这一行为由负责检票的检票员(现在是检票机)进行。

    • 一个开发者不能仿冒其他开发者生成Token
    • 终端要操作的行为和目标,如果发生了变化,能被检票方察觉。

    采用的方法是Token中会包含大量与本次操作相关信息—— 操作参数、操作目标、Token颁发者的AppKey这些都会被记录Token中。由于Token算法是公开的,因此防伪的任务被交付给现代密码学的研究成果。 我们采用HMACSHA256算法,对操作参数进行摘要并计算出签名。 为了防止开发者A冒充另一个开发者生成签名,签名使用开发者的SecretKey进行加密,因此每个开发者都必须保护好自己的SecretKey。不要把SecretKey存储或传输到不安全的地方——比如移动端、网页代码中。 由于生成Token需要传入SecretKey,Token应当只在开发者的服务端程序生成。

  • Q: 如果给终端颁发了一个Token,然后有后悔了,能撤除吗?

    A: Token是基于加密运算来验证的,因此目前萤石云平台不提供撤回Token的功能。如果出现安全问题,您可以更换您的Appkey和SecretKey。要注意:更换后,开发者之前所有颁发的Token将全部失效。各个终端需要重新向SaaS服务申请新的Token才能访问萤石云。

开发者指南

Q: 要怎么使用SDK来颁发Token

A: 请使用TokenGenerator的子类,这些子类都支持接口方法generateToken。例如生成非设备类操作的Token的方法是这样的:

// 您需要用AppKey和 SecretKey 来初始化生成器对象。生成器对象可以缓存,并支持多线程并发。
// 请注意保管好您的 AppKey 和 SecretKey。

const { NonDeviceOpsTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

const generator = new NonDeviceOpsTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

const attributes = new Map();
attributes.set('role', 'admin');

const token = generator.generateToken({
  appId: 'app01',
  userId: 'user01',
  expire: 900,
  urlPattern: '/api/v3/conference/**',
  attributes,
});

不同的业务类型,可能需要传入不同的参数。具体参数请参考API章节。

Q: 目前有那几类Tokengenerator,有什么用?

A:

| 类名 | 说明 | 用途 | | - | - | - | |NonDeviceOpsTokenGenerator | 非设备类操作授权Token | 可以访问开放平台网关,需要指定AppId,userId(终端标识)等参数后进行授权。 | | DeviceGeneralTokenGenerator | 设备操作类的授权Token | 可以访问开放平台网关,需要指定DeviceSerial,ChannelNo等参数后进行授权。 | | RTCTokenGenerator | RTC操作Token | RTCToken,用于RTC终端加入RTC会议使用。不能用于访问开放平台网关。 | | StreamTokenGenerator | 取流操作Token | 取流Token,用于进行私有流取流。不能用于访问开放平台网关。 | | GeneralResourceTokenGenerator。 | 资源访问Token | 用于访问资源服务器,可通过开放平台网关验证token。

Q: 如何成为在颁发票据的时候贯彻安全原则

A: 为什么Token的颁发者要注意颁发Token的安全?因为任何终端,只要获得了票据后,就可以凭票据访问萤石开放平台的资源。这些资源被使用往往会有以下限制——

  • 产生流量的操作会被计费
  • 可能造成使用萤石开放平台的存储资源计费
  • 可能造成网关接口访问次数被统计或因超出频率而被限流。

因为Token的颁发行为,本质上是开发者将自己的操作权限授权给Token的获得者,因此相关的费用和其他访问后果将由Token的颁发者负责。

为此,Token颁发者需要根据自己的业务特点,并且按照【权限最小原则】进行授权。由于SecretKey保管不善而造成的信息泄漏,或者由于Token权限过大(有效期过长)造成的安全隐患,应由Token签发者自行负责。

萤石开放平台设计中考虑了较多安全机制,来帮助Token颁发者限制颁发的Token的使用范围。萤石对开发者在颁发Token时的安全建议如下——

  • 设置尽可能小的Token有效时间。如果Token马上就会被接收方使用,你可以控制Token过期时间仅为10秒钟。10秒之后Token会自动失效,这将大大增加攻击者利用的难度。
  • 在Token中写入授权设备的特征码、设备序列号等操作参数,当终端持有Token在萤石云进行验证时,这些参数会被检查与Token中的是否一致。
  • 针对开放平台网关操作,设置Token参数的UrlPattern属性,限定Token持有者仅可能凭借Token访问符合该模式的URL。
  • 针对支持一次性操作的Token,设置useOnceOnly属性为true,指定该Token在萤石云上只能使用一次。
  • 针对开放平台网关操作,设置Token参数的自定义属性(setAttribute),在访问网关时也会校验这部分参数。

总之,这些措施的目的都是为了更精确的秒数Token持有者在访问萤石云平台时的行为,确保Token颁发后不会被滥用。

示例

E1:取流操作的Token

以取流Token为例,取流授权中,您需要指定取流的设备序列号和通道号,从而方式持有人利用该Token去访问其他设备。

const { StreamTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

let generator = new StreamTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

const token = generator.generateToken({
  actionType: 1,                 // 是预览还是回放
  deviceSerial: 'D12356643',     // 设备序列号
  channel: '1',
  expire: 900,                   // 取流过期时间,15分钟
  expire2: 28800                 // 取流后用户播放有效期,8小时
  terminalIP: '172.56.22.134',   // 终端IP
  isUseOnceOnly: false           // 指定该取流Token只能使用1次
});

E2: 颁发Token访问开放平台网关:授权可访问的API URL

可以在代码中设置UrlPattern,来限制Token持有者访问网关的API接口

const { NonDeviceOpsTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

let generator = new NonDeviceOpsTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

const token = generator.generateToken({
  appId: 'app01',
  userId: '',
  expire: 3600,
  urlPattern: '/api/v3/conference/**'
});

//上述代码生成了一个Token,与应用app01关联,持有者可以在1小时(3600秒)内,访问/api/v3/conference/ 开头的所有API。
//其中**可以匹配任意层级的任意URL。

URLPattern的使用规则如下

  • ? 可以匹配任意单个字符。(不含目录分隔符 /
  • * 可以匹配任意0到n个字符。(不含目录分隔符 /
  • ** 可以匹配任意层级的目录和字母。

E3:颁发Token访问开放平台网关:授权可操作的设备

对于设备操作,Token颁发者应该将操作范围限定在一个设备上或一个通道上。

const { DeviceGeneralTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

let generator = new DeviceGeneralTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

const token = generator.generateToken({
  action: 'ALL',
  deviceSerial: 'D12356643',                // 设备序列号
  channel: '1',
  terminalIP: '172.56.22.134',              // 设定该Token只能被指定终端IP使用
  urlPattern: '/api/lapp/device/capture',   // 设置该Token只能调用抓图接口
  isUseOnceOnly: true,                      // 指定该取流Token只能使用1次
  expire: 60                                // 设定有效时间
});

E4: 颁发Token访问开放平台网关:限定HTTP请求参数

对于其他类型的操作,Token颁发者应当限制请求中的关键参数。以防止Token使用者越权操作。

const { NonDeviceOpsTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

let generator = new NonDeviceOpsTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

// 指定访问开放平台API时,以下两个HTTP参数必须为指定的值。
// 注意参数名(roomid、pairid)必须和实际请求开放平台时的HTTP query参数完全一致,包括大小写。
const attributes = new Map();
attributes.set('roomid', 'room001');
attributes.set('pairid', 'pair001');

const token = generator.generateToken({
  appId: 'app01',
  userId: 'user01',
  expire: 1000,
  urlPattern: '/api/v3/conference/**',
  attributes
});

E5: 颁发RTC Token

const { RTCTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

let generator = new RTCTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

const token = generator.generateToken({
  appId: 'app01',
  userId: 'user01',   // 设置用户id
  expire: 1000,       // 设置过期时间
  roomId: '12345'     // 设置房间号
});

E6: 颁发资源访问Token

const { GeneralResourceTokenGenerator } = require('@ezviz/openplatform-sdk').Auth;

let generator = new GeneralResourceTokenGenerator();
generator.init(APP_KEY, SECRET_KEY);

const attributes = new Map();
attributes.set('strRoomId', 'ID1699430483');            //设置业务参数:strRoomId
attributes.set('customId', '7ca19da6c7164bc5ad7e0a');   //设置业务参数:customId

// 创建一个终端入会的action
const policy = [{name: 'JOIN_ROOM', attributes }];

const token = generator.generateToken({
  appid: 'f758a146b2b24fc7b9705e232bce9f02',
  expire: 604800,
  policy
});

API

Auth模块

模块方法导入

const {
  NonDeviceOpsTokenGenerator,
  DeviceGeneralTokenGenerator,
  RTCTokenGenerator,
  StreamTokenGenerator,
  GeneralResourceTokenGenerator
} = require('@ezviz/openplatform-sdk').Auth;

API详细说明

| 类名 | 方法名 | 参数 | 返回值 | 说明 | | - | - | - | - | - | | NonDeviceOpsTokenGenerator | init | (appKey: string, secretKey: string) | void | 初始化非设备类操作授权Token生成器 | | NonDeviceOpsTokenGenerator | generateToken | (options: NonDeviceOpsTokenOptions) | string | 生成非设备类操作授权Token | | DeviceGeneralTokenGenerator | init | (appKey: string, secretKey: string) | void | 初始化设备操作类的授权Token生成器 | | DeviceGeneralTokenGenerator | generateToken | (options: DeviceGeneralTokenOptions) | string | 生成设备操作类的授权Token | | RTCTokenGenerator | init | (appKey: string, secretKey: string) | void | 初始化RTC操作Token生成器 | | RTCTokenGenerator | generateToken | (options: RTCTokenOptions) | string | 生成RTC操作Token | | StreamTokenGenerator | init | (appKey: string, secretKey: string) | void | 初始化取流操作Token生成器 | | StreamTokenGenerator | generateToken | (options: StreamTokenOptions) | string | 生成取流操作Token | | GeneralResourceTokenGenerator | init | (appKey: string, secretKey: string) | void | 初始化资源访问Token生成器 | | GeneralResourceTokenGenerator | generateToken | (options: GeneralResourceTokenOptions) | string | 生成资源访问Token |

类型定义

NonDeviceOpsTokenOptions
interface NonDeviceOpsTokenOptions {
  appId?: string;                     // 应用ID
  userId?: string;                    // 用户ID
  expire: number;                     // 过期时间,单位秒
  urlPattern?: string;                // URL模式
  time?: number;                      // 当前时间,单位秒
  attributes?: Map<string, string>;   // 自定义属性
  isUseOnceOnly?: boolean;            // 是否一次性,默认false
}
DeviceGeneralTokenOptions
interface DeviceGeneralTokenOptions {
  appId?: string;                     // 应用ID
  action: string;                     // 操作类型,此处使用‘ALL’
  deviceSerial: string;               // 设备序列号
  channel: string;                    // 通道号
  expire: number;                     // 过期时间,单位秒
  resourceCatagory?: string;          // 资源类型
  terminalIP?: string;                // 终端IP
  urlPattern?: string;                // URL模式
  time?: number;                      // 当前时间,单位秒
  attributes?: Map<string, string>;   // 自定义属性
  isUseOnceOnly?: boolean;            // 是否一次性
  
}
RTCTokenOptions
interface RTCTokenOptions {
  appId: string;          // 应用ID
  userId: string;         // 用户ID
  expire: number;         // 过期时间,单位秒
  roomId: string;         // 房间号
  time?: number;          // 当前时间,单位秒
}
StreamTokenOptions
interface StreamTokenOptions {
  appId?: string;              // 应用ID
  actionType: number;          // 操作类型,0-预览,1-回放,2-对讲
  deviceSerial: string;        // 设备序列号
  channel: string;             // 通道号
  expire: number;              // 过期时间,单位秒
  expire2: number;             // 持续播放时间,单位秒
  resourceCatagory?: string;   // 资源类型
  terminalIP: string;          // 终端IP
  time?: number;               // 当前时间,单位秒
  isUseOnceOnly?: boolean;     // 是否一次性
}
GeneralResourceTokenOptions
interface GeneralResourceTokenOptions {
  appid: string;    // 应用ID
  expire: number;   // 过期时间,单位秒
  policy: Array<{name: string, attributes: Map<string, string>}>; // 策略
  time?: number;    // 当前时间,单位秒
}