# 用户鉴权 (/zh-CN/api-reference/rtm/flutter/token)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

鉴权是指在用户访问你的系统前，对其进行身份校验。用户在使用声网服务，如加入音视频通话或登录信令系统时，声网使用 Token 对其鉴权。

基于不同的传输连接，RTM SDK 提供的功能可以被划分为两种服务类型： `MESSAGE` 服务和 `STREAM` 服务。这两种服务使用的 Token 是不同的，更新 Token 的方法也不同。其中：

- `MESSAGE` 服务：使用 RTM 实例下的 `renewToken()` 方法更新 token，为 `Message Channel`、`User Channel`、`Presence`、`Storage`、`Lock`等特性提供鉴权服务。
- `STREAM` 服务： 使用 `streamChannel` 实例下的`renewToken()` 方法更新 Token，为 `Stream Channel`、`Topic` 等功能特性提供健全服务。

这两种服务都会通过 `token` 事件返回 Token 即将过期通知。你可以通过监听此事件实现 Token 自动续期的业务逻辑。Token 的有效期最长为 24 小时，声网推荐你在 Token 过期前更新 Token。本文介绍如何更新 Token。

想要了解生成和使用 Token 的更多信息，可以查看：

- [用户鉴权](/zh-CN/realtime-media/rtm/build/authentication-and-connection/user-authentication)

## renewToken [#renewtoken]

### 接口描述 [#接口描述]

为保证及时更新 Token，声网推荐你监听 `token` 回调，详见[事件监听](/zh-CN/api-reference/rtm/flutter/configuration#事件监听)。成功添加事件监听后，当 Token 还有 30 秒过期时，SDK 会触发 `token` 回调，提醒用户及时更新。

- 通过调用 `rtmClient.renewToken(String token)` 为 `MESSAGE` 服务更新 Token。
- 通过调用 `streamChannel.renewToken(String token)` 为 `STREAM` 服务更新 Token。

### 接口方法 [#接口方法]

你可以通过以下方式调用 `renewToken` 方法：

```dart
Future<(RtmStatus, RenewTokenResult?)> renewToken(String token);
```

| 参数 | 类型 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- | --- |
| `token` | String | 必填 | - | [token-flutter-html-0-1-4 details](#table-slot-token-flutter-html-0-1-4) |

<a id="table-slot-token-flutter-html-0-1-4"></a>

**token-flutter-html-0-1-4 details**

根据使用的服务类型，在该参数中填入对应 Token。

- `MESSAGE` 服务：新生成的 RTM Token。
- `STREAM` 服务：新生成的 RTC Token。

### 基本用法 [#基本用法]

```dart
class TokenResult {
    final String status;
    final String token;
    TokenResult(this.status, this.token);
}
// 定义获取 token 函数
Future<TokenResult> fetchToken({required String channelName}) async {
    // 向 Token Provider 请求 Token
    ......
    String status = "success";
    String token = "your_token_here";
    return TokenResult(status, token);
}

rtmClient.addListener({
    token:(event) => {
        if(event.channelName == '') {                                        // 当 event 中 channelName 为空时，表示 MESSAGE 服务 Token 过期
            var result = await fetchToken();                                 // 获取 MESSAGE 服务 Token
            rtmClient.renewToken(result.token);                              // 更新 MESSAGE 服务 Token
        } else {                                                             // 当 event 中 channelName 不为空时，表示 `STREAM` 服务 Token 过期
            var result = await fetchToken(channelName: event.channelName);   // 获取 STREAM 服务 Token
            streamChannel.renewToken(result.token);                          // 更新 STREAM 服务 Token
        }
    }
});
```

### 返回值 [#返回值]

调用此方法，会返回 `Future<(RtmStatus, RenewTokenResult?)>` 类型的元组数据。

- 无论该方法是否调用成功，元组的第一项都会返回一个 `RtmStatus` 类型的数据，其中字段定义如下：

  ```dart
  class RtmStatus {
      bool error;                   // 本次操作是否出错。
      String errorCode;             // 本次操作错误码。
      String operation;             // 本次操作的 API。
      String reason;                // 本次操作错误原因简述。
  }
  ```

  你可以通过检索 `errorCode` 字段的[错误码](/zh-CN/realtime-media/rtm/build/troubleshooting)了解错误原因，并找到对应的解决方法。

- 如果该方法调用成功，元组的第二项将返回一个 `RenewTokenResult` 类型的数据，定义如下：

  ```dart
  class RenewTokenResult {
      final RtmServiceType serverType;  // 服务类型
      final String channelName;         // 频道名
  }
  ```
