全部產品
Search
文件中心

ApsaraVideo Live:Token鑒權

更新時間:Jan 16, 2026

Token是阿里雲設計的一種安全保護簽名,目的是為了阻止惡意攻擊者盜用您的雲端服務使用權。您需要在服務端產生Token並下發給用戶端,用戶端SDK會基於Token發起入會請求,鑒權通過則成功入會。

前提條件

  • 登入阿里雲帳號,並開通阿里雲ApsaraVideo for Live服務。

  • 建立即時音視頻應用,擷取即時音視頻應用的AppID和AppKey,詳情請參見建立應用

範例程式碼

服務端產生(推薦)

阿里雲官方為Go/Java/Python等主流語言提供了代碼實現樣本:Token產生程式碼範例

用戶端產生(僅限開發調試階段使用)

重要

由於Token的產生需要使用AppKey,寫死在用戶端存在泄露的風險,因此強烈建議線上業務通過業務Server產生下發給用戶端

開發調試階段,如果業務Server還沒有產生Token的邏輯,可以暫時參考APIExample上的Token產生邏輯,產生臨時Token,其參考代碼如下:

Android端產生TokenAndroid/ARTCExample/KeyCenter/src/main/java/com/aliyun/artc/api/keycenter/ARTCTokenHelper.java

iOS端產生TokeniOS/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使用流程

image
  1. 用戶端向AppServer申請Token,AppServer根據規則產生Token並返回。

  2. 用戶端使用Token、appid、channelId、userId 等資訊,加入指定頻道。

  3. 阿里雲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產生過程樣本

yuque_diagram (1)

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傳入參數不一致引起入會失敗而開發的類似文法糖的使用方式。單參數入會是通過把鑒權TokenAppID、 ChannelIDNonceUserIDTimestamp通過JSON組織起來,然後把JSON字串進行Base64編碼後算出一個新的鑒權字串(Base64 Token)。

說明

後續給阿里雲反饋問題時需要提供Base64 Token或者傳入的UserName。

yuque_diagram (3)

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)

直播連麥情境

TokenAppID、 ChannelIDNonceUserIDTimestamp添加到直播連麥URL的query中,傳入SDK即可。URL包含的詳細欄位請參見直播連麥地址規則

image

樣本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=xxx
說明

live.aliyun.com是直播連麥URL固定首碼,不是一個真實的網域名稱,不可對其進行網域名稱的相關操作(比如ping,traceroute,telnet等)。

Token 到期處理

在建立 Token 時會傳入 Timestamp 欄位表示 Token 的到期時間。

使用 Token 加入頻道後:

  • 在 Token 到期前 30s,SDK 會觸發onAuthInfoWillExpire回調,可以調用refreshAuthInfo介面更新鑒權資訊。

  • Token 到期時,SDK 會觸發onAuthInfoExpired回調,如果需要繼續在會中,需要重新入會。