应用客户端在加入 IM 群聊,登录以收发实时消息进行即时通讯时,都需要传入 Token 参数,完成鉴权。此 Token 来自你的应用服务端,由应用服务端在加入房间时,根据 IM AppID、IM AppKey、 UserID、时间戳等参数实时生成。
IM 服务端在收到群聊操作请求时,会校验请求中携带的 Token 信息,如果校验不成功,进房会失败。
鉴权全流程如下。
客户端根据需要,向应用服务端申请 Token。
应用服务端生成 Token。
应用服务端将 Token 下发到客户端。
客户端使用获取到的 Token 进行群聊操作。
IM 服务端验证 Token。
应用客户端收到来自 IM SDK 的回调,获取操作结果(成功/失败)。

你可以参考 IM 提供的示例代码,在应用服务端实现 Token 的生成。
以 Golang 为例,参考以下代码:
package main
import (
"fmt"
"time"
)
func main() {
var appID int32 = 666666 // 火山控制台分配的appID
var userID int64 = 88888888 // 用户的UserID
var tokenExpireTime int64 =
time.Now().UnixNano()/int64(time.Millisecond) + 1000*60*30 // 30分钟
appKey := "Your_appKey"
token, err := GetToken(appID, userID, tokenExpireTime, appKey)
if err != nil {
fmt.Printf("get token error , err:%+v", err)
return
}
fmt.Printf("token:%s", token)
}
gopackage main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/binary"
"hash/crc32"
"math"
"github.com/pkg/errors"
)
const (
standardBase = 256
targetBase = 62
)
var alphabet = []byte{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
}
// Token token信息
type Token struct {
ID int32
Type int16
AppID int32
UserID int64
Timestamp int64
}
func GetToken(appID int32, userID, tokenExpireTime int64, appKey string) (string, error) {
token := &Token{
ID: appID,
Type: 1,
AppID: appID,
UserID: userID,
Timestamp: tokenExpireTime,
}
encrypted := make([]byte, 24)
binary.BigEndian.PutUint16(encrypted[:2], uint16(1))
binary.BigEndian.PutUint16(encrypted[2:4], uint16(token.Type))
binary.BigEndian.PutUint32(encrypted[4:8], uint32(token.AppID))
binary.BigEndian.PutUint64(encrypted[8:16], uint64(token.UserID))
binary.BigEndian.PutUint64(encrypted[16:24], uint64(token.Timestamp))
decodeKey, err := base64.StdEncoding.DecodeString(appKey)
if err != nil {
return "", errors.Wrapf(err, "[GetToken] decode appkey error , appkey:%s", appKey)
}
c, err := aes.NewCipher(decodeKey)
if err != nil {
return "", errors.Wrapf(err, "[GetToken] new cipher error , appkey:%s,decodekey:%s", appKey, decodeKey)
}
iv := decodeKey[:16]
encrypted = pkcs5Padding(encrypted, c.BlockSize())
cipher.NewCBCEncrypter(c, iv).CryptBlocks(encrypted, encrypted)
crc := crc32.ChecksumIEEE(encrypted)
output := make([]byte, 8+len(encrypted))
binary.BigEndian.PutUint32(output[:4], crc)
binary.BigEndian.PutUint32(output[4:8], uint32(token.ID))
copy(output[8:], encrypted)
return string(Encode(output)), nil
}
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func Encode(input []byte) []byte {
output := convert(input, standardBase, targetBase)
translate(output, alphabet)
return output
}
func convert(input []byte, sourceBase, targetBase int) []byte {
estimatedLength := estimateOutputLength(len(input), sourceBase, targetBase)
output := make([]byte, 0, estimatedLength)
zeroCount := 0
for _, b := range input {
if b == 0 {
zeroCount++
} else {
break
}
}
for len(input) > 0 {
quotient := make([]byte, 0, len(input))
remainder := 0
for _, b := range input {
accumulator := int(b&0xFF) + remainder*sourceBase
digit := (accumulator - (accumulator % targetBase)) / targetBase
remainder = accumulator % targetBase
if len(quotient) > 0 || digit > 0 {
quotient = append(quotient, byte(digit))
}
}
output = append(output, byte(remainder))
input = quotient
}
if zeroCount != 0 {
for i := 0; i < zeroCount; i++ {
output = append(output, 0)
}
}
for i, j := 0, len(output)-1; i < j; i, j = i+1, j-1 {
output[i], output[j] = output[j], output[i]
}
return output
}
func estimateOutputLength(inputLength, sourceBase, targetBase int) int {
return int(math.Ceil((math.Log(float64(sourceBase)) / math.Log(float64(targetBase))) * float64(inputLength)))
}
func translate(indices, dict []byte) {
for i, b := range indices {
indices[i] = dict[b]
}
}
go