在线咨询
专属客服在线解答,提供专业解决方案
工单支持
专业技术支持团队,随时响应服务需求

语聊房 Token 怎么生成:鉴权机制与过期处理

语聊房接入 RTC 必须使用 Token 鉴权,App Certificate 只能存在服务端,客户端每次进入频道前向服务端请求 Token,声网服务端验证 Token 合法后才允许用户加入。把 App Certificate 写进客户端代码,反编译就能取走,等于把整个 RTC 账户开放给任何人。

这篇文章覆盖语聊房 Token 的完整流程:服务端用 AgoraDynamicKey 生成 Token(含 Java 和 Node.js 代码示例)、Android 和 iOS 客户端如何传入 Token 加入频道、Token 即将过期时如何无感续期,以及常见鉴权错误排查和生产环境的安全注意事项。

一. 为什么 App Certificate 不能放在客户端

声网 RTC 鉴权需要两样东西:App ID(公开的,客户端可以持有)和 App Certificate(私密的,只能在服务端持有)。

Token 是用这两样东西合并生成的,带有用户 ID、频道名、权限类型和有效期信息,客户端用 Token 加入频道,声网服务端验证 Token 的合法性。

如果把 App Certificate 直接写在客户端代码里,任何人反编译 APK 或 IPA 都能拿到它,用你的 Certificate 生成任意 Token,以你的账号名义使用 RTC 服务。费用会被别人消耗,而且难以追溯。

正确的做法:App Certificate 只存在服务端,客户端每次加入频道前向服务端请求一个 Token。


二. Token 里包含什么信息

声网的 RTC Token(AccessToken2 格式)包含以下字段:

字段 说明
App ID 应用标识
频道名(Channel Name) Token 只对指定频道有效
用户 ID(UID) Token 只对指定用户 ID 有效
Token 有效期 Token 本身的过期时间
权限有效期 加入频道、发布音频/视频权限各自的有效期

重要:加入频道时使用的用户 ID 和频道名,必须和生成 Token 时填入的一致,否则鉴权会失败。


三. 服务端生成 Token

声网提供了开源的 Token 生成库 AgoraDynamicKey,支持 Java、Go、Node.js、Python、PHP、C++ 等语言,可以直接集成到你的后端服务里。

Java 示例(使用 RtcTokenBuilder2):

package io.agora.sample;

import io.agora.media.RtcTokenBuilder2;
import io.agora.media.RtcTokenBuilder2.Role;

public class TokenServer {

    // 从环境变量读取,不要硬编码在代码里
    static String appId = System.getenv("AGORA_APP_ID");
    static String appCertificate = System.getenv("AGORA_APP_CERTIFICATE");

    public static String generateToken(String channelName, int uid) {
        // token 本身的有效期(秒),建议 24 小时以内
        int tokenExpiration = 3600;
        // 频道内权限的有效期,可以和 token 有效期不同
        int privilegeExpiration = 3600;

        RtcTokenBuilder2 tokenBuilder = new RtcTokenBuilder2();
        String token = tokenBuilder.buildTokenWithUid(
            appId,
            appCertificate,
            channelName,
            uid,
            Role.ROLE_PUBLISHER,    // 语聊房上麦用户用 PUBLISHER
            tokenExpiration,
            privilegeExpiration
        );
        return token;
    }
}

角色说明:

  • Role.ROLE_PUBLISHER:有发布音频权限,对应麦位上的用户
  • Role.ROLE_SUBSCRIBER:仅订阅权限,对应观众席用户(部分场景用)

语聊房里,通常统一生成 ROLE_PUBLISHER 的 Token,由客户端通过设置 setClientRole 来控制实际的发布行为,而不是在 Token 级别区分。这样用户上麦时不需要重新获取 Token。

Node.js 示例:

const { RtcTokenBuilder, RtcRole } = require('agora-access-token');

function generateRtcToken(channelName, uid) {
    const appId = process.env.AGORA_APP_ID;
    const appCertificate = process.env.AGORA_APP_CERTIFICATE;
    const expirationTimeInSeconds = 3600;
    const currentTimestamp = Math.floor(Date.now() / 1000);
    const privilegeExpiredTs = currentTimestamp + expirationTimeInSeconds;

    const token = RtcTokenBuilder.buildTokenWithUid(
        appId,
        appCertificate,
        channelName,
        uid,
        RtcRole.PUBLISHER,
        privilegeExpiredTs
    );
    return token;
}

两种语言的逻辑完全一样,选你们服务端用的语言对应的库就行。Token 生成库代码可以从声网官方 GitHub 仓库下载。


四. 客户端加入频道时传入 Token

生成好 Token 之后,客户端通过 API 请求向服务端获取,再用 Token 加入 RTC 频道。

Android:

// 1. 先从服务端获取 Token(示例用伪代码表示网络请求)
String token = fetchTokenFromServer(channelName, uid);

// 2. 用 Token 加入频道
int result = engine.joinChannel(
    token,        // 从服务端获取的 Token
    channelName,  // 频道名,必须和生成 Token 时一致
    null,
    uid           // 用户 ID,必须和生成 Token 时一致
);

iOS(Swift):

// 1. 从服务端获取 Token
fetchTokenFromServer(channelName: channelName, uid: uid) { token in
    // 2. 用 Token 加入频道
    let options = AgoraRtcChannelMediaOptions()
    options.channelProfile = .liveBroadcasting
    options.clientRoleType = .audience  // 默认观众,上麦时再切换

    self.agoraKit.joinChannel(
        byToken: token,
        channelId: channelName,
        uid: uid,
        mediaOptions: options
    )
}

五. Token 过期怎么处理

Token 有效期到了,用户会被踢出频道。不处理 Token 过期,会导致用户在使用过程中突然掉线,体验很差。

SDK 会在 Token 过期前 30 秒触发回调,这时候去服务端换一个新 Token,再调 renewToken 更新就行,用户不会感知到任何中断。

Android 处理示例:

private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {

    // Token 即将过期(过期前 30 秒触发)
    @Override
    public void onTokenPrivilegeWillExpire(String token) {
        // 向服务端请求新 Token
        String newToken = fetchTokenFromServer(currentChannelName, currentUid);
        // 更新 Token,用户不会掉线
        engine.renewToken(newToken);
    }

    // Token 已过期(过期时触发,说明 onTokenPrivilegeWillExpire 没有及时处理)
    @Override
    public void onRequestToken() {
        // 重新获取 Token 并重新加入频道
        String newToken = fetchTokenFromServer(currentChannelName, currentUid);
        engine.joinChannel(newToken, currentChannelName, null, currentUid);
    }
};

iOS(Swift)处理示例:

extension YourViewController: AgoraRtcEngineDelegate {

    // Token 即将过期
    func rtcEngine(_ engine: AgoraRtcEngineKit,
                   tokenPrivilegeWillExpire token: String) {
        fetchTokenFromServer(channelName: currentChannelName, uid: currentUid) { newToken in
            engine.renewToken(newToken)
        }
    }

    // Token 已过期
    func rtcEngineRequestToken(_ engine: AgoraRtcEngineKit) {
        fetchTokenFromServer(channelName: currentChannelName, uid: currentUid) { newToken in
            engine.joinChannel(
                byToken: newToken,
                channelId: self.currentChannelName,
                uid: self.currentUid,
                mediaOptions: AgoraRtcChannelMediaOptions()
            )
        }
    }
}

onTokenPrivilegeWillExpireonRequestToken 的区别:前者是”快过期了,提前换”,后者是”已经过期了,没办法只能重连”。两个回调都要处理,提前换可以保证用户无感,但网络不好或者服务端响应慢时可能没来得及,这时候 onRequestToken 是兜底。


六. 测试阶段:临时 Token

开发初期,每次调试都搭一套 Token 服务太麻烦。声网控制台提供临时 Token 生成工具,可以生成最长 24 小时有效的临时 Token,只用于测试环境。

注意:临时 Token 只能用于开发测试,正式上线时必须换成自己服务端生成的 Token。临时 Token 的有效期最长 24 小时,且无法设置超过这个时间。


七. 常见错误排查

ERR_TOKEN_EXPIRED(109)

Token 过期。通常是开发阶段用了临时 Token 过期了,或者 onTokenPrivilegeWillExpire 回调没有正确处理。

ERR_INVALID_TOKEN(110)

Token 无效。可能原因:

  1. 生成 Token 时的 App ID / App Certificate 和当前 App ID 不匹配
  2. 频道名或用户 ID 和加入频道时填的不一致
  3. Token 字符串传输过程中被截断或编码错误

加入频道返回负数错误码

检查 App ID 格式是否正确(32位小写字母+数字),以及网络是否能正常访问声网服务器。


八. 生产环境的注意事项

Token 有效期设置:建议 1 ~ 24 小时,根据你的用户使用时长来定。语聊房用户一次可能待 2-3 小时,Token 有效期设短了频繁续期,设太长了安全性降低。一般设置 2-6 小时,配合 onTokenPrivilegeWillExpire 自动续期。

UID 分配:UID 是 32 位无符号整数(0 ~ 4294967295)。UID 0 表示让 SDK 自动分配,但建议在服务端分配具体的 UID,方便你关联业务用户 ID 和 RTC 用户 ID。

App Certificate 的安全存储:App Certificate 不要写在代码里,通过环境变量或密钥管理服务(如 AWS Secrets Manager、阿里云 KMS)注入到服务端程序。

在声网,连接无限可能

想进一步了解「对话式 AI 与 实时互动」?欢迎注册,开启探索之旅。

本博客为技术交流与平台行业信息分享平台,内容仅供交流参考,文章内容不代表本公司立场和观点,亦不构成任何出版或销售行为。