音视频通话 2.0
macOS
新手接入指南
产品简介
产品介绍
功能特性
产品优势
应用场景
使用限制
基本概念
产品计费
按量计费
资源包
更新日志
体验 Demo
下载 SDK 和 示例代码
快速开始
接入流程
创建应用
开通服务
快速跑通 Sample Code
集成 SDK
实现音视频通话
Token 鉴权
高级 Token 鉴权
基础功能
设置音频属性
设置视频属性
设置通话音量
屏幕共享
音频共享
通话前网络质量探测
监测发言者音量
通话中质量监测
进阶功能
音频管理
客户端音频录制
原始音频数据
美声变声与混响
耳返
自定义音频采集与渲染
音效与伴音
设置音频订阅优先级
音频裸流传输
媒体补充增强信息
视频管理
视频截图
水印
云信美颜
相芯美颜
虚拟背景
自定义视频采集
视频裸流传输
加入多房间
媒体流管理
视频流回退
媒体流加密
跨房间媒体流转发
云端录制
使用云代理
AI 融合功能
AI 降噪
AI 超分
AI 虚拟背景
最佳实践
音视频参数配置推荐
房间连接状态管理
实现音视频安全检测
API 参考
macOS API 参考
服务端 API
错误码
控制台指南
常见问题处理
FAQ
错题集
获取音频 Dump 文件
音频常见问题排查
视频常见问题排查
服务协议

Token 鉴权

更新时间: 2023/03/23 10:34:02

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

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

鉴权方式

鉴权方式说明

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

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

修改鉴权方式

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

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

操作步骤如下:

  1. 登录网易云信控制台
  2. 在左侧导航栏单击指定应用名称。
  3. 已开通功能区域中,音视频通话 2.0互动直播 2.0右侧单击功能配置

token1.png

  1. 鉴权方式区域中,选择授权方式,并单击确定
鉴权
  1. 在弹出对话框中单击确定
温馨提示

获取 Token

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

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

基本流程

uml diagram
  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请求示例如下:

curl -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 为例。

import 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格式的返回示例如下:

"Content-Type": "application/json; charset=utf-8"
{
   "code":200,
   "token":"xxxxx"  //安全认证模式下的签名。
}

方式二 在您的业务服务器根据规则自行计算 NERtc Token

基本流程

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

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

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

    请基于 App Key、App Secret 和 uid,参考如下计算规则生成 NERtc Token。

    请注意自行生成 Token 时,curTime 单位为毫秒,若传参有误会导致报错 414。

    //获取当前时间戳,单位为毫秒
    curTime = 1614764611561
    //设置过期时间,单位为秒
    ttl = 600
    //生成 signature,将 appkey、uid、curTime、ttl、appsecret 五个字段拼成一个字符串,进行 sha1 编码
    //其中 channelName 可以为空, 表示该 uid 可以使用这个 token 加入任意房间
    signature = sha1(appkey + uid + curTime + ttl + channelName + appsecret)
    //组装成 json
    json = {"signature": "xx", "curTime":1614764611561, "ttl": 600}
    //将 json 转成字符串后进行 base64 编码,生成最终的 token
    String token = JSONUtil.toJsonStr(json)
    token = Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8))
    

    该步骤交互由您自行完成,您也可以参考搭建 Token 服务器直接通过 Golang 语言实现。

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

搭建 Token 服务器

以 Golang 语言为例,您可以参考以下步骤在您的业务服务器搭建 Token Server。

此示例仅供测试使用,不建议用于生产环境。

步骤一 准备运行文件

准备一个 tokenserver.go 文件,使用如下代码:

  • App KeyApp Secret 的获取方式:登录网易云信控制台 > 选择指定应用 > App Key管理
  • uid 为用户在您应用中的 ID,请在您的业务服务器上自行管理并维护。
package main

import (
    "crypto/sha1"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
)

const (
    appkey    = "<Your App Key>"    // TODO 替换为您的应用App Key
    appsecret = "<Your App Secret>" // TODO 替换为您的应用App Secret
)

func sha1sum(s string) string {
    h := sha1.New()
    if _, err := h.Write([]byte(s)); err != nil {
        return ""
    }
    bs := h.Sum(nil)
    return fmt.Sprintf("%x", bs)
}

// See: https://doc.yunxin.163.com/nertc/docs/TQ0MTI2ODQ?platform=android#%E8%8E%B7%E5%8F%96%20Token
// genRtcToken 用于生成 *NERtc Token*
func genNERtcToken(channelName string, uid int64, ttl int) (token string, err error) {
    curTime := time.Now().UnixNano() / 1e6
    sign := sha1sum(fmt.Sprintf("%s%d%d%d%s%s", appkey, uid, curTime, ttl, channelName, appsecret))
    content, err := json.Marshal(map[string]interface{}{"signature": sign, "curTime": curTime, "ttl": ttl})
    if err != nil {
        return "", err
    }
    return base64.StdEncoding.EncodeToString(content), nil
}

type TokenRequest struct {
    ChannelName string `json:"channelName"`
    Uid         int64  `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 := genNERtcToken(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=="
}

常见问题

  • Token 过期如何处理?

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

此文档是否对你有帮助?
有帮助
我要吐槽
  • 鉴权方式
  • 鉴权方式说明
  • 修改鉴权方式
  • 获取 Token
  • 方式一 向云信服务器申请 NERTC Token
  • 基本流程
  • 服务端 getToken 接口说明
  • 方式二 在您的业务服务器根据规则自行计算 NERtc Token
  • 基本流程
  • 搭建 Token 服务器
  • 常见问题