基础 Token 鉴权
更新时间: 2024/06/26 11:32:04
网易云信 音视频通话 和 互动直播 产品中,鉴权方式分为安全模式和调试模式。如果您在 网易云信控制台 中为指定应用开启了安全模式,则对应应用的用户在加入房间时,需要通过 Token 进行身份校验。
本文介绍了网易云信支持的 鉴权方式,以及如何 生成 Token。
鉴权方式对比
鉴权方式分为安全模式和调试模式,其区别如下:
对比项 | 安全模式 | 调试模式 |
---|---|---|
鉴权方式 | 加入房间时,必须设置正确、可用的 Token,以便网易云信服务器对登录用户进行身份和权限认证。 | 加入房间时,无需设置 Token,即不对登录用户进行鉴权。 |
开启状态 | 默认开启。 | - |
安全性 | 安全性较高。 | 安全性较低,可能会有盗刷风险。 |
应用场景 | 适用于正式上线的应用。 | 适用于调试、测试阶段的应用。 |
修改鉴权方式
创建应用并开通音视频通话服务后,应用默认的鉴权方式为安全模式。网易云信建议您在应用接入和测试期间使用调试模式,并在正式上线前改为安全模式。
修改鉴权方式的操作步骤请参考 开启或关闭功能,修改路径为 音视频通话 2.0 > 功能配置 > 基础功能 > 鉴权方式。
获取 Token
安全模式 下,需要使用 NERTC Token 才能加入房间。您可以参考下文中的 两种方式 获取 NERTC Token。
方式一:自行计算 NERTC Token(推荐)
您可以在您的业务服务器中,根据规则自行计算 NERTC Token。流程如下所示:
sequenceDiagram
title: 基本流程
participant 您的 App
participant 您的业务服务器
participant 网易云信服务器
participant 网易云信 RTC SDK
Note over 您的 App, 网易云信 RTC SDK: 申请 Token
您的 App ->> 您的业务服务器: 请求 Token
您的业务服务器 -->> 您的 App: 按规则计算并返回 Token
Note over 您的 App, 网易云信 RTC SDK: 加入房间时鉴权
rect rgb(191, 223, 255)
您的 App ->> 网易云信 RTC SDK: 调用客户端 SDK API 加入房间并传入 Token
网易云信 RTC SDK ->> 网易云信服务器: 校验 Token
网易云信服务器 -->> 您的 App: 校验成功并返回成功加入房间的回调
end
流程说明如下:
-
客户端向应用服务器发起安全认证签名的请求。
该步骤交互由您自行完成,具体请参考 搭建 Token 服务器。
-
应用服务器根据规则自行计算出 NERTC Token 并返回给客户端。
该步骤由您自行实现,相应的示例代码和实现方式请参考 生成 Token 和 搭建 Token 服务器。
-
客户端通过以上步骤获取 NERTC Token 之后,可以携带 NERTC Token 加入房间。
生成 Token
请参考网易云信在 GitHub 上提供的示例代码,在您的应用服务器上生成 NERTC Token。示例代码的地址如下:
语言 | 示例代码 | 关键函数 |
---|---|---|
Java | 生成 Token-Java | getToken |
Go | 生成 Token-Go | GetToken |
Node.js | 生成 Token-Nodejs | GetToken |
PHP | 生成 Token-PHP | getToken |
Python | 生成 Token-Python | get_token |
C++ | 生成 Token-C++ | getBasicToken |
C#(dotnet) | 生成 Token-C# | GetToken |
生成 NERTC Token 的关键参数说明如下表所示。
参数 | 类型 | 描述 |
---|---|---|
channelName | String | RTC 房间名称。channelName 可以为空, 表示该 uid 可以使用这个 token 加入任意房间。 |
uid | Long | 用户在您应用中的 ID,请在您的业务服务器上自行管理并维护。 |
curTime | Long | 当前 Unix 时间戳,单位为毫秒,若传参有误会导致报错 414。 |
ttlSec | Integer | Token 过期时间,单位为秒,最大为 86400 秒(1 天)。 |
appKey | String | 请登录网易云信控制台查看您的应用对应的 AppKey 和 AppSecret,具体请参考 创建应用并获取 AppKey。 |
appSecret | String |
以 Java 语言为例,生成 Token 的示例代码如下:
Javapublic String getToken(String channelName, long uid, int ttlSec) throws Exception {
long curTimeMs = System.currentTimeMillis();
return getTokenWithCurrentTime(channelName, uid, ttlSec, curTimeMs);
}
public String getTokenWithCurrentTime(String channelName, long uid, int ttlSec, long curTimeMs) throws Exception {
if (ttlSec <= 0) {
ttlSec = defaultTTLSec;
}
DynamicToken tokenModel = new DynamicToken();
//生成 signature,将 appkey、uid、curTime、ttl、appsecret 五个字段拼成一个字符串,进行 sha1 编码
tokenModel.signature = sha1(String.format("%s%d%d%d%s%s", appKey, uid, curTimeMs, ttlSec, channelName, appSecret));
tokenModel.curTime = curTimeMs; //获取当前时间戳,单位为毫秒
tokenModel.ttl = ttlSec; //设置 Token 的过期时间,单位为秒
ObjectMapper objectMapper = new ObjectMapper();
String signature = objectMapper.writeValueAsString(tokenModel);
return Base64.getEncoder().encodeToString(signature.getBytes(StandardCharsets.UTF_8)); // 对 JSON 字符串进行 Base64 编码,返回生成的 Token 字符串
}
private String sha1(String input) throws NoSuchAlgorithmException {
MessageDigest mDigest = MessageDigest.getInstance("SHA-1");
byte[] result = mDigest.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : result) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static class DynamicToken {
public String signature;
public long curTime;
public int ttl;
}
}
搭建 Token 服务器
以 Golang 语言为例,您可以参考以下步骤在您的业务服务器搭建 Token Server。
此示例仅供测试使用,不建议用于生产环境。
步骤一:准备运行文件
准备一个 tokenserver.go
文件,使用如下代码:
GoLangpackage main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
const (
appkey = "<Your App Key>" // TODO 替换为您的应用 App Key
appsecret = "<Your App Secret>" // TODO 替换为您的应用 App Secret
)
var (
// NewTokenServer 实现见 https://github.com/netease-im/G2-API-Examples/blob/main/server/token_server/go/token/token.go
// 说明见 https://github.com/netease-im/G2-API-Examples/tree/main/server/token_server/go
tokenServer, _ = NewTokenServer(appkey, appsecret, 86400)
)
type TokenRequest struct {
ChannelName string `json:"channelName"`
Uid uint64 `json:"uid"`
TTL int `json:"ttl"`
}
func tokenHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
if r.Method != "POST" {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
content, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("error to read http body, %v", err), http.StatusBadRequest)
return
}
tokenReq := &TokenRequest{}
if err = json.Unmarshal(content, &tokenReq); err != nil {
http.Error(w, fmt.Sprintf("error to parse http body, %v", err), http.StatusBadRequest)
return
}
token, err := tokenServer.GetToken(tokenReq.ChannelName, tokenReq.Uid, tokenReq.TTL)
if err != nil {
http.Error(w, fmt.Sprintf("error to generate NERtc token, %v", err), http.StatusInternalServerError)
return
}
resp := make(map[string]interface{})
resp["token"] = token
resp["code"] = http.StatusOK
respBody, err := json.Marshal(resp)
if err != nil {
http.Error(w, fmt.Sprintf("error to compose NERtc token response, %v", err), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write(respBody)
return
}
func main() {
http.HandleFunc("/nertc-token", tokenHandler)
if err := http.ListenAndServe(":8088", nil); err != nil {
log.Fatal(err)
}
}
步骤二:本地运行服务
在本地运行以下命令。
Bashgo run server.go
步骤三:请求并获取 NERTC Token
可以使用如下示例中的 curl 命令请求 Token Server 并获得 NERTC Token。
cURLcurl --location --request POST 'localhost:8088/nertc-token' \
--header 'Content-Type: application/json' \
--data-raw '{
"channelName":"channel-881",
"uid":66******5,
"ttl":3600
}'
请求发起成功后,会得到如下响应体。
JSON{
"code": 200,
"token": "eyJjdXJUaW1lIjoxN******lZDRhZTRhOGVjMWIwIiwidHRsIjozNjAwfQ=="
}
方式二:申请 NERTC Token
您也可以向网易云信服务器申请 NERTC Token。流程如下所示:
sequenceDiagram
title: 基本流程
participant 您的 App
participant 您的业务服务器
participant 网易云信服务器
participant 网易云信 RTC SDK
Note over 您的 App, 网易云信 RTC SDK: 申请 Token
您的 App ->> 您的业务服务器: 请求 Token
您的业务服务器 ->> 网易云信服务器: 调用 getToken 接口申请 Token
网易云信服务器 -->> 您的业务服务器: 生成并返回 Token
您的业务服务器 -->> 您的 App: 返回 Token
Note over 您的 App, 网易云信 RTC SDK: 加入房间时鉴权
您的 App ->> 网易云信 RTC SDK: 调用客户端 SDK API 加入房间并传入 Token
网易云信 RTC SDK -->> 网易云信服务器: 校验 Token
网易云信服务器 -->> 您的 App: 校验成功并返回成功加入房间的回调
-
客户端向应用服务器发起安全认证签名的请求。
该步骤交互由您自行完成。
-
应用服务器调用接口 getToken,向网易云信服务器申请 NERTC Token。
请求成功,网易云信服务器会将 NERTC Token 返回给应用服务器。
-
应用服务器将获取到的 NERTC Token 返回给客户端。
-
客户端通过以上步骤获取 NERTC Token 之后,可以携带 NERTC Token 加入房间。
服务端 getToken 接口说明
- 请求 Header 的相关说明 (包括 CurTime、CheckSum)请参考 服务端 API 请求结构。
- 请注意此接口的 Content-Type 与其他音视频服务端接口有所差异,为
application/x-www-form-urlencoded;charset=utf-8
。
接口地址信息
HTMLPOST https://api.netease.im/nimserver/user/getToken.action HTTP/1.1
Content-Type:application/x-www-form-urlencoded;charset=utf-8
请求参数
参数名称 | 类型 | 是否必选 | 示例值 | 描述 |
---|---|---|---|---|
uid | Long | 必选 | 123456 | 用户 ID。 |
channelName | String | 可选 | abc | 绑定的房间名称。未指定 channelName 时,获取的 Token 可以用于加入任何房间。 |
repeatUse | Boolean | 可选 | true | 在 Token 有效期内该用户是否可以多次使用该 Token,默认为 true。
|
expireAt | int | 可选 | 640 | NERTC Token 的过期时间,过期后,该用户将无法通过此 Token 加入房间。 取值范围为 1~86400 秒,默认为 600 秒。 |
如果需要更新 NERTC Token 有效期,可以在该 Token 过期之前,重复使用同样的 uid 和 channelName 再次调用该接口,通过 expireAt
参数修改 Token 有效期。服务端不会返回新的 Token,但会更新此 Token 的有效期。
请求示例
cURL 请求示例如下:
cURLcurl -X POST -H "AppKey: go9dnk********" -H "Nonce: 4tggger********" -H "CurTime: 1443592222" -H "CheckSum: 9e9db3b6c9ab********************" -H "Content-Type: application/x-www-form-urlencoded" -d 'uid=123456' 'https://api.netease.im/nimserver/user/getToken.action'
HttpClient 请求示例如下,此处以 Java 为例。
Javaimport org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Test {
public static void main(String[] args) throws Exception{
DefaultHttpClient httpClient = new DefaultHttpClient();
String url = "https://api.netease.im/nimserver/user/getToken.action";
HttpPost httpPost = new HttpPost(url);
String appKey = "94kid09c9ig9k1loimjg012345123456";
String appSecret = "123456789012";
String nonce = "12345";
String curTime = String.valueOf((new Date()).getTime() / 1000L);
String checkSum = CheckSumBuilder.getCheckSum(appSecret, nonce ,curTime);/// checkSum 的计算方式请参考《服务端 API-服务端 API 说明-调用方式》
// 设置请求的 header
httpPost.addHeader("AppKey", appKey);
httpPost.addHeader("Nonce", nonce);
httpPost.addHeader("CurTime", curTime);
httpPost.addHeader("CheckSum", checkSum);
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// 设置请求的参数
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("uid", "123456"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
// 执行请求
HttpResponse response = httpClient.execute(httpPost);
// 打印执行结果
System.out.println(EntityUtils.toString(response.getEntity(), "utf-8"));
}
}
返回参数
参数名称 | 类型 | 示例值 | 描述 |
---|---|---|---|
code | Number | 200 | 状态码。200 表示成功调用。 |
token | String | xxxxx | 服务端返回的 Token。 |
返回示例
JSON 格式的返回示例如下:
JSON"Content-Type": "application/json; charset=utf-8"
{
"code":200,
"token":"xxxxx" //安全认证模式下的签名。
}
下一步:传递 Token 给 NERTC SDK
传递 Token 给客户端 NERTC SDK 目的是为了加入房间等操作。用户携带获取到的 uid
、channelName
和 token
,调用 NERTC SDK 具体的开发平台或者开放框架版本的 joinChannel
方法加入房间,相关 API 请参考对应的客户端 API 文档。
加入房间时,用户 ID 和房间名称需要与申请 Token 时使用的用户 ID 和房间名称一致。
JavaNERtcEx.getInstance().joinChannel("your_token", "your_channel_name", yourUid,null);
常见问题
Token 过期了怎么办?
Token 过期时,NERTC SDK 不会触发任何回调。若用户已加入房间内,不会被踢出房间,也不会影响用户的推拉流动作。再次加入房间时,若仍使用的是过期 Token,NERTC SDK 会在触发的 onJoinChannel
回调中返回相关错误码。
相关文档
您也可以参考并尝试 高级 Token 鉴权。