本文介绍如何使用 AccessToken 鉴权以及如何升级至 AccessToken2。
鉴权是指在用户访问你的系统前,对其进行身份校验。用户在使用 Agora 服务,如加入音视频通话或登录信令系统时,Agora 使用 Token 对其鉴权。
本文展示如何在服务端部署一个 RTM Token 生成器,以及如何搭建一个使用 RTM Token 鉴权的客户端。
下图展示了鉴权的基本流程:
RTM Token 在 app 服务器上生成,其有效期为 24 小时。当用户从你的 app 客户端登录到 RTM 系统时,Agora 平台会读取该 Token 中包含的信息,并进行校验。Token 包含以下信息:
开始前,请确保你的项目或使用的 Agora 产品满足如下条件:
本节介绍如何使用 Agora 提供的代码生成并提供 Token,对用户及其权限进行校验。
本节介绍如何获取生成 Token 所需的安全信息,如你的项目的 App ID 及 App 证书。
声网会给每个项目自动分配一个 App ID 作为项目唯一标识。
在声网控制台的项目管理页面,找到你的项目,点击 App ID 右侧的 图标,即可获取项目的 App ID。
参考以下步骤获取 App 证书:
在声网控制台的项目管理页面,找到你的项目,点击配置。
点击主要证书下面的复制图标,即可获取项目的 App 证书。
Token 需要在你的服务端部署生成。当客户端发送请求时,服务端部署的 Token Generator 会生成相应的 Token,再发送给客户端。
本节展示如何使用 Golang 在你的本地设备上搭建并运行一个 Token 服务器。
server.go
文件,然后贴入如下代码。将其中的 <Your App ID>
和 <Your App Certificate>
替换为你的 App ID 和 App 证书。package main
import (
rtmtokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/RtmTokenBuilder"
"fmt"
"log"
"net/http"
"time"
"encoding/json"
"errors"
"strconv"
)
type rtm_token_struct struct{
Uid_rtm string `json:"uid"`
}
var rtm_token string
var rtm_uid string
func generateRtmToken(rtm_uid string){
appID := "Your_App_ID"
appCertificate := "Your_Certificate"
expireTimeInSeconds := uint32(3600)
currentTimestamp := uint32(time.Now().UTC().Unix())
expireTimestamp := currentTimestamp + expireTimeInSeconds
result, err := rtmtokenbuilder.BuildToken(appID, appCertificate, rtm_uid, rtmtokenbuilder.RoleRtmUser, expireTimestamp)
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("Rtm Token: %s\n", result)
rtm_token = result
}
}
func rtmTokenHandler(w http.ResponseWriter, r *http.Request){
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS");
w.Header().Set("Access-Control-Allow-Headers", "*");
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
if r.Method != "POST" && r.Method != "OPTIONS" {
http.Error(w, "Unsupported method. Please check.", http.StatusNotFound)
return
}
var t_rtm_str rtm_token_struct
var unmarshalErr *json.UnmarshalTypeError
str_decoder := json.NewDecoder(r.Body)
rtm_err := str_decoder.Decode(&t_rtm_str)
if (rtm_err == nil) {
rtm_uid = t_rtm_str.Uid_rtm
}
if (rtm_err != nil) {
if errors.As(rtm_err, &unmarshalErr){
errorResponse(w, "Bad request. Please check your params.", http.StatusBadRequest)
} else {
errorResponse(w, "Bad request.", http.StatusBadRequest)
}
return
}
generateRtmToken(rtm_uid)
errorResponse(w, rtm_token, http.StatusOK)
log.Println(w, r)
}
func errorResponse(w http.ResponseWriter, message string, httpStatusCode int){
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.WriteHeader(httpStatusCode)
resp := make(map[string]string)
resp["token"] = message
resp["code"] = strconv.Itoa(httpStatusCode)
jsonResp, _ := json.Marshal(resp)
w.Write(jsonResp)
}
func main(){
// Handling routes
// RTM token from RTM uid
http.HandleFunc("/fetch_rtm_token", rtmTokenHandler)
fmt.Printf("Starting server at port 8082\n")
if err := http.ListenAndServe(":8082", nil); err != nil {
log.Fatal(err)
}
}
go.mod
文件定义导入路径及依赖项。运行如下命令来为你的 Token 服务器创建 go.mod
文件:
$ go mod init sampleServer
运行如下命令行安装依赖:
$ go get
运行如下命令行启动服务器:
$ go run server.go
本节以 Web 客户端为例,展示如何使用 Token 对客户端的用户进行鉴权。
创建一个项目文件夹,其中包含如下文件:
index.html
:用户界面client.js
:使用 RTM SDK 的 app 逻辑|
|-- index.html
|-- client.js
下载 Agora RTM SDK for Web。将 libs
中的 JS 文件保存到你的项目下。
在 index.html
中加入以下代码,创建用户界面。
<path to the JS file>
替换为你上一步保存的 JS 文件的路径。<html>
<head>
<title>RTM Token demo</title>
</head>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<body>
<h1>Token demo</h1>
<script src="<path to the JS file>"></script>
<script src="./client.js"></script>
</body>
</html>
将如下代码贴入 client.js
文件中,实现客户端鉴权逻辑。
将 <Your App ID>
替换为你的 App ID。该 App ID 必须与 Token 生成代码中的 App ID 一致。
将 <Your Host URL and port>
替换为你部署好的本地 Golang 服务器的主机 URL 和端口,如 10.53.3.234:8082
。
// login 方法参数
let options = {
token: "",
uid: ""
}
// 是否开启 Token 更新循环
let stopped = false
function sleep (time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
function fetchToken(uid) {
return new Promise(function (resolve) {
axios.post('http://<Your Host URL and port>/fetch_rtm_token', {
uid: uid,
}, {
headers: {
'Content-Type': 'application/json; charset=UTF-8'
}
})
.then(function (response) {
const token = response.data.token;
resolve(token);
})
.catch(function (error) {
console.log(error);
});
})
}
async function loginRTM()
{
// 你的 app ID
const appID = "<Your App ID>"
// 初始化客户端
const client = AgoraRTM.createInstance(appID)
// 显示连接状态变化
client.on('ConnectionStateChanged', function (state, reason) {
console.log("State changed To: " + state + " Reason: " + reason)
})
// 设置 RTM 用户 ID
options.uid = "1234"
// 获取 Token
options.token = await fetchToken(options.uid)
// 登录 RTM 系统
await client.login(options)
while (!stopped)
{
// 每 30 秒更新一次 Token。此更新频率是为了功能展示。生产环境建议每小时更新一次。
await sleep(30000)
options.token = await fetchToken(options.uid)
client.renewToken(options.token)
let currentDate = new Date();
let time = currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds();
console.log("Renew RTM token at " + time)
}
}
loginRTM()
在上述代码示例中,你可以看到 Token 与客户端的以下代码逻辑有关:
login
方法,使用 Token 和用户 ID 登录 RTM 系统。用户 ID 必须和用于生成 Token 的用户 ID 一致。renewToken
方法更新 SDK 的 Token。Agora 建议你定时(例如每小时)从服务端生成 Token 并调用 renewToken
方法更新 SDK 的 Token,保证 SDK 的 Token 一直处于有效状态。用支持的浏览器打开 index.html
文件,进入开发者模式。在控制台可以看到客户端执行以下操作:
renewToken
方法更新 Token。本节介绍 Token 生成器代码库、开发者注意事项等相关文档。
Agora 在 GitHub 上提供一个开源的 AgoraDynamicKey 仓库,支持使用 C++、Java、Go 等语言在你自己的服务器上生成 Token。
语言 | 算法 | 核心方法 | 示例代码 |
---|---|---|---|
C++ | HMAC-SHA256 | buildToken | RtmTokenBuilderSample.cpp |
Go | HMAC-SHA256 | buildToken | sample.go |
Java | HMAC-SHA256 | buildToken | RtmTokenBuilderSample.java |
Node.js | HMAC-SHA256 | buildToken | RtmTokenBuilderSample.js |
PHP | HMAC-SHA256 | buildToken | RtmTokenBuilderSample.php |
Python 2 | HMAC-SHA256 | buildToken | RtmTokenBuilderSample.py |
Python 3 | HMAC-SHA256 | buildToken | RtmTokenBuilderSample.py |
本节介绍生成 Token 的 API 参数和描述。以 C++ 为例:
static std::string buildToken(const std::string& appId,
const std::string& appCertificate,
const std::string& userAccount,
RtmUserRole userRole,
uint32_t privilegeExpiredTs = 0);
参数 | 描述 |
---|---|
appId | 你在 Agora 控制台创建项目时生成的 App ID。 |
appCertificate | 你的 App 证书。 |
userAccount | 用于登录 RTM 系统的用户 ID。你需要自行设定。支持的字符参考 login 方法中的 userId 参数。 |
userRole | 用户角色。暂时只支持一种角色,请使用默认值 Rtm_User 。 |
privilegeExpiredTs | 此参数暂不生效。你无需设置此参数。每个 RTM Token 的有效期都是 24 小时。 |
生成 RTM Token 时填入的用户 ID,需要和登录 RTM 系统时填入的用户 ID 一致。
生成 RTM Token 需要先在控制台启用对应项目的 App 证书。项目一旦开启了 App 证书,就必须使用 RTM Token 鉴权。
RTM Token 的有效期为 24 小时。
SDK 处于 CONNECTION_STATE_CONNECTED
状态时,即使 RTM Token 过期,用户也不会被踢出。用户登录时使用已过期的 RTM Token 则会返回 LOGIN_ERR_TOKEN_EXPIRED
错误。
RTM 系统只会在 RTM Token 过期且 SDK 处于 CONNECTION_STATE_RECONNECTING
状态时才会触发 onTokenExpired
回调,表示 RTM Token 已失效且重连需要新的 RTM Token。回调仅触发一次。收到这个回调时,你可以在服务端重新生成 RTM Token,然后调用 renewToken
方法,将新生成的 RTM Token 传给 SDK。
onTokenExpired
回调进行 Token 过期处理,但 Agora 推荐你通过定时(例如每小时)更新 Token 来解决 Token 过期问题。该小节引导你将 AccessToken 鉴权机制升级到 AccessToken2。
rtmtokenbuilder
导入声明:// 将原先的 "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/RtmTokenBuilder"
// 替换为 "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtmtokenbuilder2"
import (
rtmtokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtmtokenbuilder2"
"fmt"
"log"
"net/http"
"time"
"encoding/json"
"errors"
"strconv"
)
BuildToken
函数:// 原先为 result, err := rtmtokenbuilder.BuildToken(appID, appCertificate, rtm_uid, rtmtokenbuilder.RoleRtmUser, expireTimestamp)
// 现移除 rtmtokenbuilder.RoleRtmUser
result, err := rtmtokenbuilder.BuildToken(appID, appCertificate, rtm_uid, expireTimestamp)
SDK 类型 | 支持 AccessToken2 鉴权的首个版本 |
---|---|
RTM Android SDK | 1.5.0 |
RTM iOS SDK | 1.5.0 |
RTM macOS SDK | 1.5.0 |
RTM Web SDK | 1.5.0 |
RTM Windows SDK | 1.5.0 |
RTM Linux SDK | 1.5.0 |
如需使用 RESTful API,务必参照 服务端 AccessToken2 认证 传入新的请求头重新完成服务端的鉴权。
为了测试 AccessToken2 服务器是否正常运行,使用支持的浏览器打开 index.html
文件并进行以下操作: