Token是阿里雲設計的一種安全保護簽名,目的是為了阻止惡意攻擊者盜用您的雲端服務使用權。您需要在服務端產生Token並下發給用戶端,用戶端SDK會基於Token發起入會請求,鑒權通過則成功入會。
前提條件
登入阿里雲帳號,並開通阿里雲ApsaraVideo for Live服務。
建立即時音視頻應用,擷取即時音視頻應用的AppID和AppKey,詳情請參見建立應用。
範例程式碼
服務端產生(推薦)
阿里雲官方為Go/Java/Python等主流語言提供了代碼實現樣本:Token產生程式碼範例。
用戶端產生(僅限開發調試階段使用)
由於Token的產生需要使用AppKey,寫死在用戶端存在泄露的風險,因此強烈建議線上業務通過業務Server產生下發給用戶端。
開發調試階段,如果業務Server還沒有產生Token的邏輯,可以暫時參考APIExample上的Token產生邏輯,產生臨時Token,其參考代碼如下:
Android端產生Token:Android/ARTCExample/KeyCenter/src/main/java/com/aliyun/artc/api/keycenter/ARTCTokenHelper.java
iOS端產生Token:iOS/ARTCExample/Common/ARTCTokenHelper.swift
用戶端使用Token入會
當前範例程式碼為便於用戶端調試,使用的是用戶端產生 Token 的方式。強烈建議線上業務改由服務端產生 Token 並下發至用戶端,以保障安全性。
Android端使用Token入會:Android/ARTCExample/QuickStart/src/main/java/com/aliyun/artc/api/quickstart/TokenGenerate/TokenGenerateActivity.java
iOS端使用Token入會:iOS/ARTCExample/QuickStart/TokenGenerate/TokenGenerateVC.swift
實現原理
Token使用流程
用戶端向AppServer申請Token,AppServer根據規則產生Token並返回。
用戶端使用Token、appid、channelId、userId 等資訊,加入指定頻道。
阿里雲RTC服務驗證Token,用戶端成功加入頻道。
Token計算方法
Token產生相關欄位說明:
參數名稱 | 描述 |
AppID | 即時音視頻應用ID和應用Key,在直播控制台建立即時音視頻應用後會自動產生,詳細請參見擷取應用開發參數。 |
AppKey | |
ChannelID | 頻道ID,由使用者自訂,String類型,不能使用Long類型,支援數字、大小寫字母、短劃線(-)、底線(_),不超過64個字元。主播和連麥觀眾需使用同一個房間號。 |
UserId | 使用者ID,由使用者自訂,String類型,不能使用Long類型,支援數字、大小寫字母、短劃線(-)、底線(_),長度不超過64個字元。 |
Nonce | Nonce字串可以為空白,這裡推薦為空白。 |
Timestamp | 到期時間戳記(秒級)。建議預設24小時,如果設定為24小時,則取當前秒數後再增加24×60×60。 |
Token產生過程樣本:

Token產生程式碼範例:
// 1. 拼接欄位:AppID+AppKey+ChannelID+UserID+Nonce+Timestamp
// 2. 使用sha256Function Compute拼接欄位,產生token。
token = sha256(AppID+AppKey+ChannelId+UserID+Nonce+timestamp)
//樣本:
AppID = "abc",AppKey="abckey",ChannelID="abcChannel",UserID="abcUser",Nonce="",Timestamp=1699423634
token = sha256("abcabckeyabcChannelabcUser1699423634") = "3c9ee8d9f8734f0b7560ed8022a0590659113955819724fc9345ab8eedf84f31"即時音視頻情境
介紹ARTC情境下如何使用Token對用戶端加入頻道的使用者進行鑒權,ARTC SDK提供了單參入會和多參入會兩種方式,下面以Android和iOS為例。
單參數入會(推薦)
ARTC情境下提供單參數入會的API。單參數入會的形式主要是為瞭解決客戶自身伺服器與App傳入參數不一致引起入會失敗而開發的類似文法糖的使用方式。單參數入會是通過把鑒權Token、AppID、 ChannelID、Nonce、UserID和Timestamp通過JSON組織起來,然後把JSON字串進行Base64編碼後算出一個新的鑒權字串(Base64 Token)。
後續給阿里雲反饋問題時需要提供Base64 Token或者傳入的UserName。

Base64 Token產生程式碼範例
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()Node.js程式碼範例
'use strict'
const crypto = require('crypto')
function create_base64_token(appid, appkey, channelid, userid) {
let timestamp = Math.floor(Date.now() / 1000 + 24 * 60 * 60)
let string_builder = appid + appkey + channelid + userid + timestamp.toString()
let token = crypto.createHash('sha256').update(string_builder).digest('hex')
let base64tokenJson = {
appid:appid,
channelid:channelid,
userid:userid,
nonce:'',
timestamp:timestamp,
token:token
}
let base64token = Buffer.from(JSON.stringify(base64tokenJson), 'utf-8').toString('base64')
return base64token
}
let appid = "your_appid";
let appkey = "your_appkey";
let channel_id = "your_channel_id";
let user_id = "your_user_id";
let base64token = create_base64_token(appid, appkey, channel_id, user_id)
console.log(base64token)xRust程式碼範例
use chrono::{Duration, Utc};
use sha2::{Sha256, Digest};
use serde_json::json;
use base64::encode;
fn create_base64_token(appid: &str, appkey: &str, channel_id: &str, user_id: &str) -> String {
// Calculate the expiration timestamp (24 hours from now)
let timestamp = (Utc::now() + Duration::hours(24)).timestamp();
// Concatenate the strings
let string_builder = format!("{}{}{}{}{}", appid, appkey, channel_id, user_id, timestamp);
// Calculate the SHA-256 hash
let mut hasher = Sha256::new();
hasher.update(string_builder);
let token = hasher.finalize();
let token_hex = format!("{:x}", token);
// Create the JSON object
let token_json = json!({
"appid": appid,
"channelid": channel_id,
"userid": user_id,
"nonce": "",
"timestamp": timestamp,
"token": token_hex
});
// Convert the JSON object to a string and encode it in Base64
let base64_token = encode(token_json.to_string());
base64_token
}
fn main() {
let appid = "your_appid";
let appkey = "your_appkey";
let channel_id = "your_channel_id";
let user_id = "your_user_id";
let token = create_base64_token(appid, appkey, channel_id, user_id);
println!("Base64 Token: {}", token);
}App調用API樣本
用戶端從服務端擷取Base64 Token後,加入房間。
Android端:
// channelid, userid傳入null即可;用戶端如果要傳入channelid、userid但是必須要和產生token用的一致,客戶可以使用這個特性進行校正伺服器和用戶端參數是否一致 // base64Token是base64後的token // username是方便排查問題時客戶傳入的標識 mAliRtcEngine.joinChannel(base64Token, null, null, "username");iOS端:
// channelid, userid傳入null即可;用戶端如果要傳入channelid、userid但是必須要和產生token用的一致,客戶可以使用這個特性進行校正伺服器和用戶端參數是否一致 // base64Token是base64後的token // username是方便排查問題時客戶傳入的標識 [self.engine joinChannel:base64Token channelId:nil userId:nil name:@"username" onResultWithUserId:nil];
多參數入會
ARTC 情境下仍然保留多參入會的 API,通過 AliRtcAuthInfo 資料結構儲存使用者的多參入會 Token 及使用者資訊進行鑒權。
加入頻道時使用的頻道 ID 和使用者識別碼 必須與產生 Token 時的一致。
Android端:
// 需要傳入多參入會token及使用者資訊 AliRtcAuthInfo authInfo = new AliRtcAuthInfo(); authInfo.appId = appId; authInfo.channelId = channelId; authInfo.userId = userId; authInfo.timestamp = timestamp; authInfo.nonce = nonce; authInfo.token = token; // 入會 mAliRtcEngine.joinChannel(authInfo, "");iOS端:
// 需要傳入多參入會token及使用者資訊 let authInfo = AliRtcAuthInfo() authInfo.appId = appId authInfo.channelId = channelId authInfo.nonce = nonce authInfo.userId = userId authInfo.timestamp = timestamp authInfo.token = authToken // 入會 self.rtcEngine?.joinChannel(authInfo, name: nil)
直播連麥情境
將Token及AppID、 ChannelID、Nonce、UserID和Timestamp添加到直播連麥URL的query中,傳入SDK即可。URL包含的詳細欄位請參見直播連麥地址規則。
樣本URL
連麥/主播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=xxxlive.aliyun.com是直播連麥URL固定首碼,不是一個真實的網域名稱,不可對其進行網域名稱的相關操作(比如ping,traceroute,telnet等)。
Token 到期處理
在建立 Token 時會傳入 Timestamp 欄位表示 Token 的到期時間。
使用 Token 加入頻道後:
在 Token 到期前 30s,SDK 會觸發
onAuthInfoWillExpire回調,可以調用refreshAuthInfo介面更新鑒權資訊。Token 到期時,SDK 會觸發
onAuthInfoExpired回調,如果需要繼續在會中,需要重新入會。