# 部署 Token 服务器 (/zh-CN/realtime-media/rtm/build/authentication-and-connection/token-generation)

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

Token 需要在你的服务端部署生成。当客户端发送请求时，服务端部署的 Token Generator 会生成相应的 Token，再发送给客户端。本文展示如何为 AccessToken2 在服务端部署一个 RTM Token 生成器。

## 前提条件 [#前提条件]

开始前，请确保你的项目或使用的声网产品满足如下条件：

- [Golang](https://golang.org/) 1.14 以上版本，GO111MODULE 设置为开启。

  :::info[信息]
  如果你使用的是 Go 1.16 及以上版本，GO111MODULE 已默认开启。详见 [New module changes in Go 1.16](https://blog.golang.org/go116-module-changes)。
  :::

## 实现部署 Token 服务器 [#实现部署-token-服务器]

本节展示如何使用 Golang 在你的本地设备上搭建并运行一个 Token 服务器，生成并提供 Token。

:::info[信息]
此示例服务器仅用于演示，请勿用于生产环境中。
:::

1. 创建一个 `server.go` 文件，然后贴入如下代码。将其中的 `Your_App_ID` 和 `Your_Certificate` 替换为你的 App ID 和 App 证书。

    ```go
    package main

    import (
        rtmtokenbuilder "github.com/AgoraIO/Tools/DynamicKey/AgoraDynamicKey/go/src/rtmtokenbuilder2"
        "fmt"
        "log"
        "net/http"
        "time"
        "encoding/json"
        "errors"
        "strconv"
    )

    type rtm_token_struct struct{
        Uid_rtm string `json:"uid"`
    }

    var rtm_token string
    var rtm_uid string

    // 使用 RtmTokenBuilder 来生成 RTM Token
    func generateRtmToken(rtm_uid string){

        appID := "Your_App_ID"
        appCertificate := "Your_Certificate"
        // AccessToken2 过期的时间，单位为秒
        expireTimeInSeconds := uint32(3600)
        currentTimestamp := uint32(time.Now().UTC().Unix())
        expireTimestamp := currentTimestamp + expireTimeInSeconds

        result, err := rtmtokenbuilder.BuildToken(appID, appCertificate, rtm_uid, expireTimestamp)
        if err != nil {
            fmt.Println(err)
        } else {
            fmt.Printf("Rtm Token: %s\n", result)

        rtm_token = result

        }
    }

    func rtmTokenHandler(w http.ResponseWriter, r *http.Request){
        w.Header().Set("Content-Type", "application/json;charset=UTF-8")
            w.Header().Set("Access-Control-Allow-Origin", "*")
            w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS");
            w.Header().Set("Access-Control-Allow-Headers", "*");

            if r.Method == "OPTIONS" {
                w.WriteHeader(http.StatusOK)
                return
            }

            if r.Method != "POST" && r.Method != "OPTIONS" {
                http.Error(w, "Unsupported method. Please check.", http.StatusNotFound)
                return
            }


            var t_rtm_str rtm_token_struct
            var unmarshalErr *json.UnmarshalTypeError
            str_decoder := json.NewDecoder(r.Body)
            rtm_err := str_decoder.Decode(&t_rtm_str)

            if (rtm_err == nil) {
                rtm_uid = t_rtm_str.Uid_rtm
            }

            if (rtm_err != nil) {
                if errors.As(rtm_err, &unmarshalErr){
                errorResponse(w, "Bad request. Please check your params.", http.StatusBadRequest)
                } else {
                errorResponse(w, "Bad request.", http.StatusBadRequest)
            }
            return
        }

            generateRtmToken(rtm_uid)
            errorResponse(w, rtm_token, http.StatusOK)
            log.Println(w, r)
    }


    func errorResponse(w http.ResponseWriter, message string, httpStatusCode int){
        w.Header().Set("Content-Type", "application/json")
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.WriteHeader(httpStatusCode)
        resp := make(map[string]string)
        resp["token"] = message
        resp["code"] = strconv.Itoa(httpStatusCode)
        jsonResp, _ := json.Marshal(resp)
        w.Write(jsonResp)

    }

    func main(){
        // 使用 int 型 uid 生成 RTM Token
        http.HandleFunc("/fetch_rtm_token", rtmTokenHandler)

        fmt.Printf("Starting server at port 8082\n")

        if err := http.ListenAndServe(":8082", nil); err != nil {
            log.Fatal(err)
        }
    }
    ```

2. `go.mod` 文件定义导入路径及依赖项。运行如下命令来为你的 Token 服务器创建 `go.mod` 文件：

   ```shell
   $ go mod init sampleServer
   ```

3. 运行如下命令行安装依赖：

   ```shell
   $ go get
   ```

4. 运行如下命令行启动服务器：

   ```shell
   $ go run server.go
   ```

:::info[信息]
如果你需要生成一个同时具备 RTC 和 RTM 权限的 Token，请参考[如何生成具备 RTC 和 RTM 权限的 Token？](/zh-CN/reference/faq/integration/rtc_rtm_token)。
:::

## 参考 [#参考]

### AccessToken2 生成器代码 [#accesstoken2-生成器代码]

声网在 GitHub 上提供一个开源的 [AgoraDynamicKey](https://github.com/AgoraIO/Tools/tree/master/DynamicKey/AgoraDynamicKey) 仓库，支持使用 C++、Java、Go 等语言在你自己的服务器上生成 Token。

| 语言 | 算法 | 核心方法 | 示例代码 |
| -------- | ----------- | ---------- | ---------------- |
| C++ | HMAC-SHA256 | [buildToken](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/cpp/src/RtmTokenBuilder2.h) | [RtmTokenBuilder2Sample.cpp](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/cpp/sample/RtmTokenBuilder2Sample.cpp) |
| Go | HMAC-SHA256 | [buildToken](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/go/src/rtmtokenbuilder2/rtmtokenbuilder.go) | [sample.go](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/go/sample/rtmtokenbuilder2/sample.go) |
| Java | HMAC-SHA256 | [buildToken](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/java/src/main/java/io/agora/rtm/RtmTokenBuilder2.java) | [RtmTokenBuilder2Sample.java](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/java/src/main/java/io/agora/sample/RtmTokenBuilder2Sample.java) |
| PHP | HMAC-SHA256 | [buildToken](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/php/src/RtmTokenBuilder2.php) | [RtmTokenBuilder2Sample.php](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/php/sample/RtmTokenBuilder2Sample.php) |
| Python 2 | HMAC-SHA256 | [buildToken](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/python/src/RtmTokenBuilder2.py) | [RtmTokenBuilder2Sample.py](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/python/sample/RtmTokenBuilder2Sample.py) |
| Python 3 | HMAC-SHA256 | [buildToken](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/python3/src/RtmTokenBuilder2.py) | [RtmTokenBuilder2Sample.py](https://github.com/AgoraIO/Tools/blob/master/DynamicKey/AgoraDynamicKey/python3/sample/RtmTokenBuilder2Sample.py) |

### BuildToken API 参考 [#buildtoken-api-参考]

本节介绍生成 AccessToken2 的 API 参数和描述。以 Golang 为例：

```go
func BuildToken(appId string, appCertificate string, userId string, expire uint32) (string, error) {
    token := accesstoken.NewAccessToken(appId, appCertificate, expire)

    serviceRtm := accesstoken.NewServiceRtm(userId)
    serviceRtm.AddPrivilege(accesstoken.PrivilegeLogin, expire)
    token.AddService(serviceRtm)

    return token.Build()
}
```

| 参数               | 描述                                                         |
| ----------------- | ------ |
| `appId`              | 你在声网控制台创建项目时生成的 App ID。                   |
| `appCertificate`     | 你的 App 证书。                                              |
| `userId`        | 用户 ID，用于标识用户或设备。为区分各用户和设备，你需要确保 `userId` 全局唯一，并且在用户或设备的生命周期内保持不变。                                            |
| `expire` | Token 的有效时长（秒），最长有效期为 24 小时。 |
