注意:本文于 2021 年 12 月 20 日更新,使用了 Node.js token 服务器 2.0.0 版本。
目前,视频聊天应用的安全性是一个热门话题,随着远程工作和虚拟事件的频率越来越高,人们对安全的需求也随之增加。
在声网Agora 平台内,有一层安保是以 token 认证的形式出现的。token 是用一组给定输入生成的动态密钥,声网Agora 平台使用 token 对用户进行身份验证。
声网Agora 为其 RTC 和 RTM SDK 提供 token 鉴权。本指南将教大家如何使用 Express 和 NodeJS 构建简单的微服务,从而生成 Agora RTC token。因为 RTM 和 RTC 遵循相似的运行模式,所以该示例也适用于 RTM。
前期准备
新建项目
首先,创建一个新的文件夹,在该文件夹中打开一个终端窗口。然后,在终端中运行 npm init
来设置项目。 接下来,会出现创建项目提示。 我使用的是默认设置,大家可以进行自定义设置。
现在,项目已经创建完成,可以使用以下命令添加 NPM 依赖项( express、agora-access-token 和 dotenv):
npm install express agora-access-token dotenv
构建 Express 服务器
目前项目已经设置完毕,大家可以在自己喜欢用的代码编辑器中打开该文件夹,查看 package.json
,你会注意到入口文件是 index.js
,但我们的项目中没有该文件,所以我们必须创建一个新文件并将其命名为 index.js
。
在 index.js
文件中,我们会从引用模块开始。 从 Express
中,我们需要 Express 对象。从 agora-access-token
中,我们会用 ES6 的解构赋值来提取对 RtcTokenBuilder
和 RtcRole
对象的引用。我们还将使用包中的 dotenv
作为环境变量:
const express = require('express');
const {RtcTokenBuilder, RtcRole} = require('agora-access-token');
const dotenv = require('dotenv');
我们创建一个 .env
文件并添加声网Agora 资质和将用来监听请求的端口,用来定义我们的变量:
APP_ID=970XXXXX...
APP_CERTIFICATE=5CFXXXXX...
PORT=8080
接下来,定义 app
常量,该常量会把 Express
对象实体化,并支持我们设置自己的服务器:
const app = express();
在为 Express 服务器设置 GET 终端之前,我们需要定义访问端点时调用的函数。第一个函数(nocache
)将应用响应头,这将强制浏览器不能缓存响应,确保我们总能获得最新的 token。 大家能注意到,我们在最后调用了 next()
方法,因为该函数是该系列的第一个中间件函数。因此我们需要调用 next()
,让 Express 继续执行该系列中下一个函数。
>const nocache = (req, resp, next) => {
resp.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
resp.header('Expires', '-1');
resp.header('Pragma', 'no-cache');
next();
};
第二个函数(generateAccessToken
)将处理请求并返回 JSON 响应。 现在,我们将定义该函数,并在完成 Express 服务器的设置后添加主体。 这是该系列中的最后一个函数,因此我们不需要 next 参数/函数。
const generateAccessToken = (req, resp) => { };
接下来,我们要定义一个 GET
终端 /rtc
,传入 nochache
和 generateAccessToken
函数中。
app.get('/access_token', nocache, generateAccessToken);
创建 Express 服务器的最后一步,我们将执行 .listen()
方法,在服务器准备就绪并侦听给定端口后传入 port 并回调。
>app.listen(PORT, () => {
console.log(`Listening on port: ${PORT}`);
});
生成 Agora RTC Token
现在我们已经完成了 Express 服务器的设置,准备将功能添加到 generateAccessToken 函数中。我们将从设置响应头开始,确保不会遇到任何 CORS 问题。
const generateRTCToken = (req, resp) => {
resp.header('Access-Control-Allow-Origin', '*');
获取请求参数
接下来,我们将检查 channelName
请求参数,这是必要参数,因此,如果未定义 channelName
,我们则需要返回带有 500 响应码的错误和一个带有错误参数的 JSON对象。
...
const channelName = req.params.channel;
if (!channelName) {
return resp.status(500).json({ 'error': 'channel is required' });
}
对于 uid
和 role
,我们将执行类似的检查:
...
let uid = req.params.uid;
if(!uid || uid === '') {
return resp.status(500).json({ 'error': 'uid is required' });
}
// get role
let role;
if (req.params.role === 'publisher') {
role = RtcRole.PUBLISHER;
} else if (req.params.role === 'audience') {
role = RtcRole.SUBSCRIBER
} else {
return resp.status(500).json({ 'error': 'role is incorrect' });
}
接下来的几个参数( uid , role , expirationTime)不是必要的,所以我们只需根据需要将其指认为默认值就好了。
对于uid
,我们将默认值设置为 0
,这使得我们可以生成 “通配符” ,其可以用任何 uid
加入指定频道。 这仅适用于安全性较低的情况下(或在开发过程中),所有用户都可以共享一个 token。
一个低安全性的例子是直播,任何人都可以加入其中并以观众身份观看。
对于频道角色,我们将每个用户默认为 audience
,并且仅检查请求是否传达到 broadcaster
那里,在其他方面的值都可以忽略。
请注意:只有默认的情况下,Agora 平台才能执行加入频道的特权,要启用其他特权,您需要通过 Agora 支持 进行开通。
对于有效时间
,我们将默认设置为3600秒
,这使用户在权限到期之前有一个小时的时间加入频道。 关于截止时间要注意一件事,是token的权限时效必须是一个整数,例如从1970年1月1日开始。我们将使用当前时间,并添加时效。
// get uid
let uid = req.query.uid;
if(!uid uid == ‘’) {
uid = 0;
}
// get role
let role = RtcRole.SUBSCRIBER;
if (req.query.role == ‘publisher’) {
role = RtcRole.PUBLISHER;
}
// get the expire time
let expireTime = req.query.expireTime;
if (!expireTime expireTime == ‘’) {
expireTime = 3600;
} else {
expireTime = parseInt(expireTime, 10);
}
// calculate privilege expire time
const currentTime = Math.floor(Date.now() / 1000);
const privilegeExpireTime = currentTime + expireTime;
构建 Token
现在,我们已经具备了构建 token 的所有条件,现在可以使用 RtcTokenBuilder
对象的 buildTokenWithUid
生成 token 了。
const token = RtcTokenBuilder.buildTokenWithUid(APP_ID, APP_CERTIFICATE, channelName, uid, role, privilegeExpireTime);
返回响应
生成 token 的最后一步是返回包含 token 的 JSON 响应:
...
return resp.json({ 'rtcToken': token });
}
测试 Token 服务器
让我们回到 package.json
并在 scripts
对象中添加 start
命令。 开始命令将执行 node index.js
命令,以便可以运行服务器实例。
{
"scripts": {
"start": "node index.js"
},
}
启动服务器
我们回到命令提示符窗口并使用新命令:npm start
服务器实例侦听后,我们将在终端窗口中看到“正在侦听端口:8080。
测试端点
现在我们的服务器实例已经处于运行状态,接下来我们要打开网络浏览器进行测试。 对于这些测试,我们将尝试一些省略各种查询参数的少量变体。
我们将从省略所有查询参数开始:
localhost:8080/access_token
这将显示:
{“rtcToken”:“0062ec0d84c41c4442d88ba6f5a2beb828bIAD9qg4N4hd04MvaY6A72m4BjYmO/7+xnRMinaI0ncLzkAx+f9gAAAAAEACS0zcn9gASXwEAAQCGvRBf”}
接下来,我们将通过 “test” 作为 channelName:
localhost:8080/access_token?channelName=test
这将可以输出任何用户都能使用的 token。
{“token”:“0062ec0d84c41c4442d88ba6f5a2beb828bIAD9qg4N4hd04MvaY6A72m4BjYmO/7+xnRMinaI0ncLzkAx+f9gAAAAAEACS0zcn9gASXwEAAQCGvRBf”}
我们可以继续对其余查询参数进行测试,然后会得到与上述情况类似的响应。
localhost:8080/access_token?channelName=test&role=subscriberlocalhost:8080/access_token?channelName=test&role=subscriber&uid=1234localhost:8080/access_token?channelName=test&role=subscriber&uid=1234&expireTime=6400
完成啦!
以上就是所有步骤啦! 如果你没跟上编码过程或想看成品,我已将所有代码上传到了 GitHub。
感谢你抽出宝贵的时间阅读我的教程,如有任何疑问,请在下方评论。 如果你发现有任何改进的空间,欢迎提交你的拉取请求~~
原文作者:Hermes Frangoudis
原文链接:https://www.agora.io/en/blog/how-to-build-a-token-server-for-agora-applications-using-nodejs/