Pano开发者中心
  • 开发者中心
  • 下载中心

›RESTful API

新手入门

  • 简介
  • 名词解释
  • 创建第一个应用

规则说明

  • Channel ID命名规则
  • 权限控制
  • 计费说明
  • 频道最大时长说明
  • 每月一万分钟免费说明
  • 布局参数说明
  • 水印

场景方案

    教育行业

    • 1vN互动小班课
    • 互动直播大班课

快速接入

  • 简介
  • 音视频

    • Windows (C++)
    • iOS (Objective-C)
    • Android (Java)
    • Web
    • Electron
    • Flutter
    • React Native
    • Unity

    白板

    • Windows (C++)
    • iOS (Objective-C)
    • Android (Java)
    • Web
    • Electron
    • Flutter
    • React Native

高级功能(RTC)

  • 简介
  • 屏幕共享
  • 分组讨论
  • 状态回调
  • 设备诊断
  • 音量指示
  • 控制声音
  • 声卡操作
  • 混音/伴音
  • 混响
  • 耳返
  • 变声
  • 美颜
  • 音视频数据回调
  • 音视频外部采集
  • 收发多路视频
  • 多窗口渲染
  • 性能检测
  • 截图
  • 反馈

高级功能(RTS)

  • 简介
  • 白板

    • Windows (C++)
    • iOS (Objective-C)
    • Android (Java)
    • Web
    • Flutter

    标注

    • 视频标注
    • 共享标注
    • 外部标注

    消息

    • 消息服务

    远程控制

    • 远程控制

操作实践

  • 切换大小屏

RESTful API

  • 基本格式
  • 生成Token
  • 频道管理
  • 云端录制
  • CDN推流
  • 文档转码
  • 消息服务
  • 服务端消息通知

SDK API

  • SDK接口说明
  • Windows (C++)
  • macOS/iOS (Objective-C)
  • Android (Java)
  • Web SDK (IE专用版)
  • Web SDK

    • 浏览器兼容性
    • RtcEngine
    • GroupManager
    • RtcWhiteboard
    • RtsService
    • RtcMessage
    • Annotation
    • Constants

更新记录

  • 简介
  • Windows
  • macOS
  • iOS
  • Android
  • Electron
  • Flutter
  • React Native
  • Unity
  • Web(全功能SDK)
  • Web(RTS SDK)
  • Web(IE专用音视频SDK)

帮助

  • FAQ
  • 更多帮助

生成Token

生成方式

SDK 到 Pano Cloud 的所有交互都需要使用 Token,Token的生成方式有两种。

  • 第一种是 App Server(应用服务器)通过 RESTful API 向 Pano 服务器获取。
  • 第二种是 App Server(应用服务器)按照 Pano 定义的规则自行计算。
    此方式需要相应的 SDK 版本才能识别,最低 SDK 版本要求如下:
    • Windows/macOS/iOS/Android: 1.4.1
    • Web: 1.3.4
    • Web Whiteboard: 2.1.0
    • Electron: 1.0.4
    • Flutter/React Native: 0.9.6

向Pano获取

请求示例

POST /auth/token
Host: api.pano.video
Content-Type: application/json
Authorization: PanoSign <PanoSign>
Tracking-Id: ef9b2acc8e1f4d598090eb6d9cbe8596

{
  "channelId": "HelloPano",     // String,必填,频道ID
  "userId": "12345",            // String,必填,用户ID
  "privileges": 0,              // int,   可选,权限
  "channelDuration": 60,        // int,   可选,频道最大时长,单位为分钟,默认为0(表示不限时长)
  "duration": 86400,            // int,   可选,token有效期,单位为秒,默认24小时
  "size": 100,                  // int,   可选,频道人数上限
  "delayClose": 0               // int,   可选,白板延迟关闭时间,单位为秒,默认为0,最长24小时
}

参数说明

  • PanoSign - 请参考权限控制
  • channelId - 请参考Channel ID命名规则
  • userId - 请参考User ID
  • privileges - 请参考Token Privileges
  • channelDuration - 频道最大时长,如需限制频道时长,可以使用此参数。另请参考频道最大时长说明。

    频道开始时间取决于频道内第一位用户的加入时间;频道最大时长取决于第一位用户携带的 channelDuration。当时间到达时Pano服务器会自动结束频道并踢出所有用户。

  • duration - token有效期(有效期内token可重复使用),可配置小于等于24小时的有效期。

    客户端加入频道时,Pano服务器会校验token的有效性,超过有效期则无法加入频道。
    向Pano获取token时,有效期起点为Pano服务器生成该token的时间点。

  • size - 频道人数上限,单个频道容纳的人数上限,默认为100。

    如果默认的人数上限不能满足应用需求,比如语聊房、视频会议等场景,通常需要较高的人数上限,而有的场景可能需要限制为较低的人数上限,请联系技术支持了解调整该默认值的方法。

  • delayClose - 白板延迟关闭时间,所有人都离开后延迟多久关闭白板频道。默认为0(立即关闭/不延迟),如果大于0,当所有人都离开后,白板频道会延迟关闭。

    如果 channelDuration 时间到达,或者主动调用服务端 API 关闭频道,则 delayClose 失效。

响应码说明

HTTP状态码错误码描述
200正常返回
403Authorization.Type.InvalidHTTP请求头Authorization类型不对
403Authorization.Signature.InvalidHTTP请求头Authorization 值有误,请检查signature签名信息
403App.Status.Errorapp 状态可能不对,请到控制台检查app是否禁用
403Org.Status.Error公司信息状态不对,请检查是否欠费
403Invalid.Parameter.Value请求参数不合法,请检查是否按文档规定传递参数
404InvalidEntity.NotFoundapp 信息找不到,请查看appId是否正确
406App.Secret.Emptyapp Secret 信息有误,请到控制台获取正确app Secret
406Sign.Error请检查PanoSign 是否按照规定生成签名信息
500Server.Error服务器内部出错

响应示例

请求正常处理的返回示例:

200 OK
{
  "token": "0100000AUHZUTER......cClLFAtM="      // 省略了中间部分字符串
}

请求出现错误的返回示例请参考:返回状态码

自行计算

如果开发者需要自行生成token,出于安全考虑,我们强烈建议在应用服务器上进行计算并下发给客户端使用。如无特别必要,不要在客户端计算token,否则可能存在潜在的安全风险。

规则介绍

Token由五部分组成,用.拼接在一起,格式为<version>.<appId>.<timestamp>.<params>.<signature>,各字段含义如下:

  • <version> - 版本号,固定为02。
  • <appId> - 应用ID,请登录 控制台 后切换到「应用管理」查看应用ID。
  • <timestamp> - 当前UTC时间戳(精确到秒),该时间戳与joinParams中的duration值相加,得到token的有效期(也就是说,自行计算token时,token的有效期起点为 timestamp 对应的时间点)。Pano服务器会校验时间戳的有效性,所以请注意设置正确的时间(建议同步NTP)。

    joinParams 请参考 向Pano获取token 时传入的body(请求示例中大括号内的内容)。

  • <params> - 频道参数,由joinParams计算获得,计算规则为:
    base64(json(joinParams)) // 对 joinParams 进行 JSON 编码后再进行 base64 编码
    
  • <signature> - 签名,由<version>、<appId>、<timestamp>、<params>、<appSecret>计算获得,计算规则为:
    signature = base64(HmacSHA256(version+appId+timestamp+params, appSecret))
    

示例代码

可以参考以下示例代码来生成Token。

Java
Go
Python2
Python3
PHP
package com.example.lib;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
/* [注意] 如果开发者需要自行生成token,出于安全考虑,我们强烈建议在应用服务器上进行计算并下发给客户端使用。
如无特别必要,不要在客户端计算token,否则可能存在潜在的安全风险。

如果确需在客户端计算,请注意,android.util.Base64 和 java.util.Base64 结果可能不一致。
根据开发者反馈,android.util.Base64 的 encodeToString 的默认行为会为编码结果添加换行符(\n)。
请注意消除相应差异,以 java.util.Base64 结果为准,否则后续token鉴权将会失败。
使用 android.util.Base64 的 encodeToString 时,尝试将 flags 参数从 DEFAULT 改为 NO_WRAP。
*/


public class MyClass {
static final String APP_ID = "Your appId";
static final String APP_SECRET = "Your appSecret";
// 此处直接使用 JSON 编码后的 joinParams(joinParams 请按实际情况配置并自行对其进行 JSON 编码)
static String jsonJoinParams = "{\"channelId\":\"1234\",\"userId\":\"1234\",\"channelDuration\":60,\"privileges\":0,\"duration\":86400,\"size\":25,\"delayClose\":0}";

public static String signature(String data, String appSecret) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(appSecret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(data.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(signData);
}

public static String generatePanoToken(String appId, String appSecret, String jsonJoinParams) throws Exception {
String version = "02";
long timestamp = System.currentTimeMillis() / 1000L;
String params = Base64.getEncoder().encodeToString(jsonJoinParams.getBytes("UTF-8"));
String signContent = new StringBuilder().append(version).append(appId).append(timestamp).append(params).toString();
String signatureValue = signature(signContent, appSecret);
return new StringBuilder()
.append(version).append(".")
.append(appId).append(".")
.append(timestamp).append(".")
.append(params).append(".")
.append(signatureValue).toString();
}

public static void main(String[] args) {
try {
String token = generatePanoToken(APP_ID, APP_SECRET, jsonJoinParams);
System.out.println(token);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package main

import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"time"
)

func signature(signContent string, appSecret string) string {
mac := hmac.New(sha256.New, []byte(appSecret))
mac.Write([]byte(signContent))
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}

func generatePanoToken(appId string, appSecret string, jsonJoinParams string) string {
version := "02"
timestamp := time.Now().Unix()
params := base64.StdEncoding.EncodeToString([]byte(jsonJoinParams))
signContent := fmt.Sprintf("%s%s%d%s", version, appId, timestamp, params)
signatureValue := signature(signContent, appSecret)
return fmt.Sprintf("%s.%s.%d.%s.%s", version, appId, timestamp, params, signatureValue)
}

func main() {
const appId string = "Your appId"
const appSecret string = "Your appSecret"
// 此处直接使用 JSON 编码后的 joinParams(joinParams 请按实际情况配置并自行对其进行 JSON 编码)
var jsonJoinParams string = "{\"channelId\":\"1234\",\"userId\":\"1234\",\"channelDuration\":60,\"privileges\":0,\"duration\":86400,\"size\":25,\"delayClose\":0}"
var token string = generatePanoToken(appId, appSecret, jsonJoinParams)
fmt.Printf(token)
}
# coding=utf-8
import base64
import hmac
import time
import json
from hashlib import sha256


def signature(signContent, appSecret):
return base64.b64encode(hmac.new(appSecret, signContent, digestmod=sha256).digest())


def generatePanoToken(appId, appSecret, joinParams):
version = "02"
timestamp = str(int(time.time()))
params = base64.b64encode(json.dumps(joinParams))
signContent = version + appId + timestamp + params
signatureValue = signature(signContent, appSecret)
return version + "." + appId + "." + timestamp + "." + params + "." + signatureValue


appId = "Your appId"
appSecret = "Your appSecret"
# joinParams 请按实际情况配置,此处仅为示例
joinParams = {"channelId": "1234", "userId": "1234", "channelDuration": 60, "privileges": 0, "duration": 86400, "size": 25, "delayClose": 0}
token = generatePanoToken(appId, appSecret, joinParams)
print(token)
import base64
import hmac
import time
import json
from hashlib import sha256


def signature(signContent, appSecret):
return base64.b64encode(hmac.new(bytes(appSecret, 'utf-8'), bytes(signContent, 'utf-8'), digestmod=sha256).digest()).decode('utf-8')


def generatePanoToken(appId, appSecret, joinParams):
version = "02"
timestamp = str(int(time.time()))
params = base64.b64encode(bytes(json.dumps(joinParams), 'utf-8')).decode('utf-8')
signContent = version + appId + timestamp + params
signatureValue = signature(signContent, appSecret)
return version + "." + appId + "." + timestamp + "." + params + "." + signatureValue


appId = "Your appId"
appSecret = "Your appSecret"
# joinParams 请按实际情况配置,此处仅为示例
joinParams = {"channelId": "1234", "userId": "1234", "channelDuration": 60, "privileges": 0, "duration": 86400, "size": 25, "delayClose": 0}
token = generatePanoToken(appId, appSecret, joinParams)
print(token)
<?php
$appId = "Your appId";
$appSecret = "Your appSecret";
$timestamp = time();
// joinParams 请按实际情况配置,此处仅为示例
$joinParams = ["channelId" => "1234", "userId" => "1234", "channelDuration" => 60, "privileges" => 0, "duration" => 86400, "size" => 25, "delayClose" => 0];

$token = getToken($appId, $appSecret, $timestamp, $joinParams);
echo $token;

function getToken($appId, $appSecret, $timestamp, $joinParams){
$version = "02";
$params = base64_encode(json_encode($joinParams));
$signData = $version . $appId . $timestamp . $params;
$signature = base64_encode(hash_hmac("sha256", $signData, $appSecret, true));
return $version . "." . $appId . "." . $timestamp . "." . $params . "." . $signature;
}

// End of file

下面是本地生成Token的结果示例:

02.abcdefghijklmnopq01234567890.1622211277.eyJjaGFubmVsSWQiOiIxMjM0IiwidXNlcklkIjoiMTIzNCIsImNoYW5uZWxEdXJhdGlvbiI6NjAsInByaXZpbGVnZXMiOjAsImR1cmF0aW9uIjo4NjQwMCwic2l6ZSI6MjUsImRlbGF5Q2xvc2UiOjB9.7bsKmTjVC2te+W4+n7XxqbrZE+VrFaxRVkTZobacaWg=
Last updated on 2022/8/15
← 基本格式频道管理 →
  • 生成方式
  • 向Pano获取
    • 请求示例
  • 自行计算
    • 规则介绍
    • 示例代码
浙ICP备20002645号 ©2019-2022 Pano拍乐云