前提條件
登入阿里雲帳號,並開通阿里雲ApsaraVideo for Live服務。
已在直播控制台建立即時音視頻應用,請參見建立即時音視頻應用。
您已經擷取AppID/AppKey。具體操作,請參見查詢AppKey。
背景資訊
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結構透傳至App側,App側將參數原封不動的透傳至ARTC SDK,並把其中的資料在App側進行本地收集,在進行阿里雲支援人員時貼上相關資訊。
方式二(此方式為單參數入會):將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程式碼範例
/**
* 根據 appid,appkey,channelId,userId,nonc,timestamp 產生 token
*
* @param appid 應用ID。在控制台應用管理頁面建立和查看。
* @param appkey 在控制台應用管理頁面建立和查看。
* @param channelId 房間 ID
* @param userId 使用者識別碼
* @return token
*/
public static String createBase64Token(String appid, String appkey, String channelId, String userId) {
/* 到期時間戳記最大24小時 */
long timestamp = Calendar.getInstance().add(Calendar.HOUR_OF_DAY, 24).getTimeInMillis() / 1000;
String stringBuilder = appid +
appkey +
channelId +
userId +
timestamp;
String token = getSHA256(stringBuilder);
JSONObject tokenJson = new JSONObject();
tokenJson.put("appid", appid);
tokenJson.put("channelid", channelId);
tokenJson.put("userid", userId);
tokenJson.put("nonce", "");
tokenJson.put("timestamp", timestamp);
tokenJson.put("gslb",new String[]{"https://gw.rtn.aliyuncs.com"});
tokenJson.put("token", token);
String base64Token = Base64.encodeToString(JSON.toJSONBytes(tokenJson),Base64.NO_WRAP);
return base64Token;
}
/**
* 字串簽名
*
* @param str 輸入源
* @return 返回簽名
*/
public static String getSHA256(String str) {
MessageDigest messageDigest;
String encodestr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
encodestr = byte2Hex(messageDigest.digest());
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodestr;
}
private static String byte2Hex(byte[] bytes) {
StringBuilder stringBuffer = new StringBuilder();
String temp = null;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
展開查看Python程式碼範例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import hashlib
import datetime
import time
import base64
import json
def create_token(app_id, app_key, channel_id, user_id, timestamp):
h = hashlib.sha256()
h.update(str(app_id))
h.update(str(app_key))
h.update(str(channel_id))
h.update(str(user_id))
h.update(str(timestamp))
token = h.hexdigest()
return token
def main():
app_id = 'xxxxxx'
app_key = 'xxxxxxxx'
channel_id = 'abcChannel'
user_id = 'abcUser1'
expire = datetime.datetime.now() + datetime.timedelta(days=1)
timestamp = int(time.mktime(expire.timetuple()))
# timestamp = 1699423634
token = create_token(app_id, app_key, channel_id, user_id, timestamp)
print(token)
jsonToken = {'appid':app_id,
'channelid':channel_id,
'userid':user_id,
'nonce':'',
'timestamp':timestamp,
'gslb':['https://gw.rtn.aliyuncs.com'],
'token':token
}
# String base64Token = Base64.encodeToString(JSON.toJSONBytes(tokenJson),Base64.NO_WRAP);
print(json.dumps(jsonToken))
base64Token = base64.b64encode(json.dumps(jsonToken).encode())
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];
多參數入會
多參數入會是鑒權的Token及計算Token的參數通過一個authinfo參數送入SDK的方式,使用此方式時需要伺服器側把Token及相關的參數全部發送至App,App將參數解析為authinfo結構後不做任何變更直接調用SDK。
後續給阿里雲反饋問題時需要提供authinfo或者傳入的UserName。
伺服器側程式碼範例
展開查看Java程式碼範例
/**
* 根據 appid,appkey,channelId,userId,nonc,timestamp 生層 token
*
* @param appid 應用ID。在控制台應用管理頁面建立和查看。
* @param appkey 在控制台應用管理頁面建立和查看。
* @param channelId 房間 ID
* @param userId 使用者識別碼
* @param timestamp 到期時間戳記
* @return token
*/
public static String createToken(String appid, String appkey, String channelId, String userId) {
/* 到期時間戳記最大24小時 */
long timestamp = Calendar.getInstance().add(Calendar.HOUR_OF_DAY, 24).getTimeInMillis() / 1000;
String stringBuilder = appid +
appkey +
channelId +
userId +
timestamp;
return getSHA256(stringBuilder);
}
/**
* 字串簽名
*
* @param str 輸入源
* @return 返回簽名
*/
public static String getSHA256(String str) {
MessageDigest messageDigest;
String encodestr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
encodestr = byte2Hex(messageDigest.digest());
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodestr;
}
private static String byte2Hex(byte[] bytes) {
StringBuilder stringBuffer = new StringBuilder();
String temp = null;
for (byte aByte : bytes) {
temp = Integer.toHexString(aByte & 0xFF);
if (temp.length() == 1) {
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
App調用API樣本
展開查看Android側Java程式碼範例
// appid,channelid,userid,nonce,timestamp,token必須和伺服器計算的一致
// username是方便排查問題時客戶傳入的標識
AliRtcAuthInfo userInfo = new AliRtcAuthInfo();
userInfo.setAppId("xxx");
userInfo.setChannelId("xxx");
userInfo.setUserId("xxx");
userInfo.setNonce("xxx");
userInfo.setTimestamp(xxx);
userInfo.setGslb(new String[]{"https://gw.rtn.aliyuncs.com"});
userInfo.setToken("xxx");
mAliRtcEngine.joinChannel(userInfo, "username");
展開查看iOS側OC程式碼範例
// appid,channelid,userid,nonce,timestamp,token必須和伺服器計算的一致
// username是方便排查問題時客戶傳入的標識
AliRtcAuthInfo *authInfo = [[AliRtcAuthInfo alloc] init];
NSMutableArray *gslb = [[NSMutableArray alloc] init];
[gslb addObject:@"https://gw.rtn.aliyuncs.com"];
authInfo.appId = @"xxx";
authInfo.channelId = @"xxx";
authInfo.userId = @"xxx";
authInfo.nonce = @"";
authInfo.timestamp = xxxxx;
authInfo.gslb = gslb;
authInfo.token = @"";
[self.engine joinChannel:authInfo 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,telent等)。