当前页面展示的文档已停止维护,给您带来不便请谅解,单击链接可跳转至当前产品介绍页面 >>

基础 Token 鉴权

更新时间: 2024/11/18 11:08:13

网易云信音视频通话和互动直播产品中,鉴权方式分为安全模式和调试模式。如果您在控制台中为指定应用开启了安全模式,则对应应用的用户在加入房间时,需要通过 Token 进行身份校验。

本文档为您介绍鉴权方式Token 的生成方式

鉴权方式

鉴权方式说明

鉴权方式分为安全模式和调试模式,其区别如下:

安全模式 调试模式
鉴权方式 默认开启。加入房间时,必须设置正确、可用的 Token,以便网易云信服务器对登录用户进行身份和权限认证。安全性较高 加入房间时,无需设置 Token,即不对登录用户进行鉴权。安全性较低,可能会有盗刷风险
应用场景 适用于正式上线的应用。 适用于调试、测试阶段的应用。

修改鉴权方式

创建应用并开通音视频通话服务后,应用默认的鉴权方式为安全模式。网易云信建议您在应用接入和测试期间使用调试模式,并在正式上线前改为安全模式。

请谨慎选择鉴权方式,若您在控制台设置应用的鉴权方式为安全模式,但该 App 用户加入房间时未设置 Token,会导致用户加入房间失败,同时报错 403。

操作步骤如下:

  1. 登录网易云信控制台

  2. 在首页单击指定应用名称。

  3. 产品总览区域,单击音视频通话 2.0 产品选项卡中的功能配置

    功能配置.png

  4. 单击基础功能页签,在鉴权方式区域中,单击编辑,选择鉴权方式,并单击保存

Token鉴权.png

选择token鉴权方式.png

  1. 在弹出对话框中单击确定

获取 Token

安全模式下,需要使用 NERTC Token 才能加入房间。其中您可以通过以下两种方式获取 NERTC Token:

方式一 在您的业务服务器根据规则自行计算 NERtc Token(推荐)

基本流程

sequenceDiagram
    participant 应用层
    participant 业务服务器
    participant 云信服务器
    participant NERtcSDK

    Note over 应用层, NERtcSDK: 申请 Token
    应用层 ->> 业务服务器: 请求 Token
    业务服务器 -->> 应用层: 按规则计算并返回 Token

    Note over 应用层, NERtcSDK: 加入房间时鉴权
    rect rgb(191, 223, 255)
    应用层 ->> NERtcSDK: 调用客户端 SDK API 加入房间并传入 Token
    NERtcSDK ->> 云信服务器: 校验 Token
    云信服务器 -->> 应用层: 校验成功并返回成功加入房间的回调
    end

流程说明如下:

  1. 客户端向应用服务器发起安全认证签名的请求。

    该步骤交互由您自行完成,具体请参考搭建 Token 服务器

  2. 应用服务器根据规则自行计算出 NERtc Token 并返回给客户端。

    该步骤由您自行实现,相应的示例代码和实现方式请参考生成 Token搭建 Token 服务器

  3. 客户端通过以上步骤获取 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

Flutter 端暂不支持高级鉴权功能,引入生成 Token 的示例代码后,您只需要调用 getToken 方法生成 Token 即可,不需要调用 getPermissionKey 方法生成权限密钥。

生成 NERtc Token 的关键参数说明如下表所示。

参数 类型 描述
channelName String RTC 房间名称。channelName 可以为空, 表示该 uid 可以使用这个 token 加入任意房间。
uid Long 用户在您应用中的 ID,请在您的业务服务器上自行管理并维护。
curTime Long 当前 Unix 时间戳,单位为毫秒,若传参有误会导致报错 414。
ttlSec Integer Token 过期时间,单位为秒,最大为 86400 秒(1 天)。
appKey String 请登录网易云信控制台查看您的应用对应的AppKeyAppSecret,具体请参见创建应用并获取 AppKey
appSecret String

以 Java 语言为例,生成 Token 的示例代码如下:

public 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 文件,使用如下代码:

package 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)
	}
}

步骤二 本地运行服务

在本地运行以下命令。

go run server.go

步骤三 请求并获取 NERtc Token

可以使用如下示例中的 curl 命令请求 Token Server 并获得 NERtc Token。

curl --location --request POST 'localhost:8088/nertc-token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "channelName":"channel-881",
    "uid":66******5,
    "ttl":3600
}'

请求发起成功后,会得到如下响应体。

{
    "code": 200,
    "token": "eyJjdXJUaW1lIjoxN******lZDRhZTRhOGVjMWIwIiwidHRsIjozNjAwfQ=="
}

方式二 向云信服务器申请 NERTC Token

基本流程

sequenceDiagram
    participant 应用层
    participant 业务服务器
    participant 云信服务器
    participant NERtcSDK

    Note over 应用层, NERtcSDK: 申请 Token
    应用层 ->> 业务服务器: 请求 Token
    业务服务器 ->> 云信服务器: 调用 getToken 接口申请 Token
    云信服务器 -->> 业务服务器: 生成并返回 Token
    业务服务器 -->> 应用层: 返回 Token

    Note over 应用层, NERtcSDK: 加入房间时鉴权
    应用层 ->> NERtcSDK: 调用客户端 SDK API 加入房间并传入 Token
    NERtcSDK -->> 云信服务器: 校验 Token
    云信服务器 -->> 应用层: 校验成功并返回成功加入房间的回调
  1. 客户端向应用服务器发起安全认证签名的请求。

    该步骤交互由您自行完成。

  2. 应用服务器调用接口 getToken,向云信服务器申请 NERTC Token。

    请求成功,云信服务器会将 NERTC Token 返回给应用服务器。

  3. 应用服务器将获取到的 NERTC Token 返回给客户端。

  4. 客户端通过以上步骤获取 NERTC Token 之后,可以携带 NERTC Token 加入房间。

服务端 getToken 接口说明

  • 请求 Header 的相关说明(包括 CurTimeCheckSum)请参考服务端 API 请求结构
  • 请注意此接口的 Content-Type 与其他音视频服务端接口有所差异,为 application/x-www-form-urlencoded;charset=utf-8

接口地址信息

POST 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。此 uid 为用户在您应用中的 ID,请在您的业务服务器上自行管理并维护。
channelName String 可选 abc 绑定的房间名称。未指定 channelName 时,获取的 Token 可以用于加入任何房间。如果首次获取 Token 时通过 channelName 设置了 Token 对应的房间名称,并使用该 Token 加入房间,之后该用户加入该房间的 Token 都应绑定此房间名称。
repeatUse Boolean 可选 true 在 Token 有效期内该用户是否可以多次使用该 Token,默认为 true。
  • true:有效期内可多次使用。
  • false:有效期内只能使用一次。
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 传给客户端用于加入房间

用户携带获取到的 uidchannelNametoken ,调用 joinChannel 方法加入房间。

加入房间时,用户 ID 和房间名称需要与申请 Token 时使用的用户 ID 和房间名称一致。

_engine.joinChannel(token,channelName,uid);

常见问题

Token 过期如何处理?

答:Token 过期时,SDK 不会触发任何回调。若用户已加入房间内,不会被踢出房间,也不会影响用户的推拉流动作;再次加入房间时,若仍使用的是过期 Token,SDK 会在触发的 onJoinChannel 回调中返回相关错误码。

此文档是否对你有帮助?
有帮助
去反馈
  • 鉴权方式
  • 鉴权方式说明
  • 修改鉴权方式
  • 获取 Token
  • 方式一 在您的业务服务器根据规则自行计算 NERtc Token(推荐)
  • 基本流程
  • 生成 Token
  • 搭建 Token 服务器
  • 方式二 向云信服务器申请 NERTC Token
  • 基本流程
  • 服务端 getToken 接口说明
  • 将 Token 传给客户端用于加入房间
  • 常见问题