全部产品
Search
文档中心

视频直播:Token鉴权

更新时间:Jul 18, 2024

本文介绍实时音视频场景下,Token字段的生成规则。

前提条件

  • 已注册阿里云账号,并开通阿里云视频直播服务。

  • 已在直播控制台创建实时音视频应用,请参见创建实时音视频应用

  • 您已经获取AppID/AppKey。具体操作,请参见查询AppKey

背景信息

Token是阿里云设计的一种安全保护签名,目的是为了阻止恶意攻击者盗用您的云服务使用权。您需要在相应SDK的登录函数中提供AppIDUserIDChannelIdNonceTimeStampToken信息。其中AppID用于标识您的应用,UserID用于标识您的用户,而Token是基于上述参数(AppIDAppKeyChannelIDNonceUserIDTimestamp)计算得出。因此,攻击者很难通过伪造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、 ChannelIDNonceUserIDTimestamp)生成JSON结构透传至App侧,App侧将参数原封不动的透传至ARTC SDK,并把其中的数据在App侧进行本地收集,在进行阿里云技术支持时贴上相关信息。

  • 方式二(此方式为单参数入会):将Token及计算用的5个参数(AppID、 ChannelIDNonceUserIDTimestamp)生成JSON后进行Base 64编码,通过一个字符串Base 64 Token透传至App侧,App侧透传Base 64 Token至ARTC SDK,同时传入排查问题使用的UserName字段。

  • 方式三:将Token及计算用的5个参数(AppID、 ChannelIDNonceUserIDTimestamp)生成URL,传入直播连麦SDK即可。

image

业务场景

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    用户 ID
 * @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    用户 ID
 * @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等)。