背景信息
Token是阿里云设计的一种安全保护签名,目的是为了阻止恶意攻击者盗用您的云服务使用权。您需要在相应SDK的登录函数中提供AppID、UserID、ChannelId、Nonce、TimeStamp和Token信息。其中AppID用于标识您的应用,UserID用于标识您的用户,而Token是基于上述参数(AppID、 AppKey、ChannelID、Nonce、UserID和Timestamp)计算得出。因此,攻击者很难通过伪造Token盗用您的云服务流量。
阿里云SDK为了让客户更加方便的使用,针对不同业务场景封装了ARTC场景API入会、直播连麦API入会两种使用形式。
Token原理及计算方法
Token的计算原理及方法如下,开发者可以根据如下方法计算Token。
// 1. AppID+AppKey+ChannelID+UserID+Nonce+timestamp 产生原始字符串
// 2. sha256计算后转为token字符串
// 3. 客户可以通过下面的示例看看自己的算法是否正确
// AppID="abc",AppKey="abckey",ChannelID="abcChannel",UserID="abcUser",Nonce="",timestamp=1699423634
// token = sha256("abcabckeyabcChannelabcUser1699423634") = "3c9ee8d9f8734f0b7560ed8022a0590659113955819724fc9345ab8eedf84f31"
// 4. 特别说明: Nonce字符串可以为空,这里推荐为空;timestamp取当前秒数后再增加24*60*60
token = sha256(AppID+AppKey+ChannelId+UserID+Nonce+timestamp)
Token生成相关字段说明:
参数名称 | 描述 |
AppID | 实时音视频应用ID,在直播控制台创建实时音视频应用后会自动生成。请参见创建实时音视频应用。 |
AppKey | 在直播控制台实时音视频应用管理页面,可以查询AppKey,请参见查询AppKey。 |
channelID | 频道ID,由用户自定义,支持数字、大小写字母、短划线(-)、下划线(_),不超过64个字符。主播和连麦观众需使用同一个房间号。 |
userId | 用户ID,由用户自定义,支持数字、大小写字母、短划线(-)、下划线(_),长度不超过64个字符。 |
nonce | Nonce字符串可以为空,这里推荐为空。 |
timestamp | 过期时间戳(秒级)。不能超过24小时,建议默认24小时。 |
服务器侧计算上面的Token后,根据业务情况有如下两种处理方式。
方式一(此方式为单参数入会):将Token及计算用的5个参数(AppID、 ChannelID、Nonce、UserID和Timestamp)生成JSON后进行Base 64编码,通过一个字符串Base 64 Token透传至App侧,App侧透传Base 64 Token至ARTC SDK,同时传入排查问题使用的UserName字段。
方式二:将Token及计算用的5个参数(AppID、 ChannelID、Nonce、UserID和Timestamp)生成URL,传入直播连麦SDK即可。

业务场景
ARTC场景
ARTC场景下提供单参数入会的API。单参数入会的形式主要是为了客户自身服务器与App传入参数不一致引起入会失败而开发的类似语法糖
的使用方式。
单参数入会是通过把鉴权Token、计算的6个参数、gslb参数通过JSON组织起来,然后把JSON字符串进行Base64编码后算出一个新的鉴权字符串。这样客户的Appserver和App只需要通过一个参数进行交互,避免数据不一致造成的接入失败。
后续给阿里云反馈问题时需要提供Base64Token或者传入的UserName。
服务器侧代码示例
展开查看Java代码示例
package com.example;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Calendar;
import org.json.JSONObject;
public class App {
public static String createBase64Token(String appid, String appkey, String channelid, String userid) {
// Calculate the expiration timestamp (24 hours from now)
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.HOUR_OF_DAY, 24);
long timestamp = calendar.getTimeInMillis() / 1000;
// Concatenate the strings
String stringBuilder = appid + appkey + channelid + userid + timestamp;
// Calculate the SHA-256 hash
String token = sha256(stringBuilder);
// Create the JSON object
JSONObject base64tokenJson = new JSONObject();
base64tokenJson.put("appid", appid);
base64tokenJson.put("channelid", channelid);
base64tokenJson.put("userid", userid);
base64tokenJson.put("nonce", "");
base64tokenJson.put("timestamp", timestamp);
base64tokenJson.put("token", token);
// Convert the JSON object to a string and encode it in Base64
String jsonStr = base64tokenJson.toString();
String base64token = Base64.getEncoder().encodeToString(jsonStr.getBytes(StandardCharsets.UTF_8));
return base64token;
}
private static String sha256(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
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();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String appid = "your_appid";
String appkey = "your_appkey";
String channel_id = "your_channel_id";
String user_id = "your_user_id";
String base64token = createBase64Token(appid, appkey, channel_id, user_id);
System.out.println("Base64 Token: " + base64token);
}
}
展开查看go代码示例
package main
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"time"
)
func createBase64Token(appid, appkey, channelID, userID string) (string, error) {
// Calculate the expiration timestamp (24 hours from now)
timestamp := time.Now().Add(24 * time.Hour).Unix()
// Concatenate the strings
stringBuilder := appid + appkey + channelID + userID + fmt.Sprintf("%d", timestamp)
// Calculate the SHA-256 hash
hasher := sha256.New()
hasher.Write([]byte(stringBuilder))
token := hasher.Sum(nil)
// Convert the hash to a hexadecimal string using encoding/hex
tokenHex := hex.EncodeToString(token)
// Create the JSON object
tokenJSON := map[string]interface{}{
"appid": appid,
"channelid": channelID,
"userid": userID,
"nonce": "",
"timestamp": timestamp,
"token": tokenHex,
}
// Convert the JSON object to a string and encode it in Base64
jsonBytes, err := json.Marshal(tokenJSON)
if err != nil {
return "", err
}
base64Token := base64.StdEncoding.EncodeToString(jsonBytes)
return base64Token, nil
}
func main() {
appid := "your_appid"
appkey := "your_appkey"
channelID := "your_channel_id"
userID := "your_user_id"
token, err := createBase64Token(appid, appkey, channelID, userID)
if err != nil {
fmt.Println("Error creating token:", err)
return
}
fmt.Println("Base64 Token:", token)
}
展开查看Python代码示例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import hashlib
import datetime
import time
import base64
import json
def create_base64_token(app_id, app_key, channel_id, user_id):
expire = datetime.datetime.now() + datetime.timedelta(days=1)
timestamp = int(time.mktime(expire.timetuple()))
h = hashlib.sha256()
h.update(str(app_id).encode('utf-8'))
h.update(str(app_key).encode('utf-8'))
h.update(str(channel_id).encode('utf-8'))
h.update(str(user_id).encode('utf-8'))
h.update(str(timestamp).encode('utf-8'))
token = h.hexdigest()
jsonToken = {'appid':app_id,
'channelid':channel_id,
'userid':user_id,
'nonce':'',
'timestamp':timestamp,
'token':token
}
base64Token = base64.b64encode(json.dumps(jsonToken).encode())
return base64Token
def main():
app_id = 'your_appid'
app_key = 'your_appkey'
channel_id = 'your_channel_id'
user_id = 'your_user_id'
base64Token = create_base64_token(app_id, app_key, channel_id, user_id)
print(base64Token)
if __name__ == '__main__':
main()
App调用API示例
Android侧Java代码示例:
// channelid, userid传入null即可;客户端如果要传入channelid、userid但是必须要和产生token用的一致,客户可以使用这个特性进行校验服务器和客户端参数是否一致
// base64Token是base64后的token
// username是方便排查问题时客户传入的标识
mAliRtcEngine.joinChannel(base64Token, null, null, "username");
iOS侧OC代码示例:
// channelid, userid传入null即可;客户端如果要传入channelid、userid但是必须要和产生token用的一致,客户可以使用这个特性进行校验服务器和客户端参数是否一致
// base64Token是base64后的token
// username是方便排查问题时客户传入的标识
[self.engine joinChannel:base64Token channelId:nil userId:nil name:@"username" onResultWithUserId:nil];
直播连麦
直播连麦,主播与观众连麦或主播PK的推拉流地址:
连麦/主播PK场景推流地址:
artc://live.aliyun.com/push/633?timestamp=1685094092&token=fe4e674ade****6686&userId=718&sdkAppId=xxx
连麦/主播PK场景拉流地址:
artc://live.aliyun.com/play/633?timestamp=1685094092&token=fe4e674ade****6686&userId=718&sdkAppId=xxx
说明 live.aliyun.com是直播连麦URL固定前缀,不是一个真实的域名,不可对其进行域名的相关操作(比如ping,traceroute,telnet等)。