Token生成指导

1. Token的使用流程图

2. Token生成步骤

2.1 创建项目生成AppID及AppKey

创建项目生成AppID及AppKey的具体方法,可以查看 快速开始

2.2 sha1算法生成Token

Token 生成规则

sha1算法利用AppID及AppKey生成Token,Token采用类jwt格式:分为头部和数据载荷,形式:header(头部).signture(数据载荷)。

2.2.1 生成header

header 部分采用为json 字符串,然后进行base64 编码。

1. json字符串格式

Jsonmsg = { "user_id": uid, "room_id":roomId, "app_id": = appId } header=base64(Jsonmsg) ;

2. 生成base64编码

Headerbase64=base64(jsonmsg) ;

2.2.2 生成signature

1. 时间戳获取

时间戳为UTC时间,精确到秒,截取最后10位,作为最终的时间戳。
伪代码如下:

unixts = getutctimes() unixts=format(“%10u”, unixts)

2. 随机数生成

随机生成32位的无符号整形数,然后转为16进制,保持8位长度,作为随机数。
伪代码如下:

random = random() random=format(“%08x”, random)

2.2.3 签名生成

1. 格式化字符串

strformat = format(“%s%s%d%d%s”, userid, appid, unixts, random, roomid)\\

2. 通过sha1 编码 加密key 为seckey

sign = HmacSign(appCertificate, strformat, HMAC_LENGTH);\\

3. 拼接加密串

signture = format(“%s%d%d”, sign, unixts, random)\\

2.2.4 拼接最终的Token

token = header+ “.”+ signture\\

2.3 参考实现代码

  • Go 参考代码如下
package authcenter
import (
    "crypto/hmac"
    "crypto/sha1"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "errors"
    "fmt"
    "strings"
)

func GenerateRoomToken(uid, appId, roomId, appCertificate string, unixTs int64, randomInt uint32) (string, error) {
    mapCombine := make(map[string]interface{})
    mapCombine["user_id"] = uid
    mapCombine["room_id"] = roomId
    mapCombine["app_id"] = appId
    jsonCombine, err := json.Marshal(mapCombine)
    if err != nil {
        return "", errors.New("SYSTEM_ERROR")
    }

    singnatureStr := Generate(uid, appId, appCertificate, roomId, unixTs, randomInt)
    encodeStr := base64.StdEncoding.EncodeToString([]byte(jsonCombine))
    strCombineToken := encodeStr + "." + singnatureStr

    return strCombineToken, nil
}

func Generate(uId, appID, appCertificate, roomId string, unixTs int64, randomInt uint32) string {
    return generateDynamicKey(uId, appID, appCertificate, roomId, unixTs, randomInt)
}

func generateDynamicKey(uId, appID, appCertificate, roomId string, unixTs int64, randomInt uint32) string {
    unixTsStr := fmt.Sprintf("%010d", unixTs)
    randomIntStr := fmt.Sprintf("%08x", randomInt)
    signature := generateSignature(uId, appID, appCertificate, roomId, unixTsStr, randomIntStr)
    buffer := strings.Join([]string{signature, unixTsStr, randomIntStr}, "")
    return buffer
}

func generateSignature(uId, appID, appCertificate, roomId, unixTsStr, randomIntStr string) string {
    buffer := strings.Join([]string{uId, appID, unixTsStr, randomIntStr, roomId}, "")
    signature := hmac.New(sha1.New, []byte(appCertificate))
    signature.Write([]byte(buffer))
    return hex.EncodeToString(signature.Sum(nil))
}
  • Java 参考代码如下
import java.io.ByteArrayOutputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class signature {
    // 调用方法生成token
    public static String generateToken(String uid, String roomid, String appid, String seckey){
        long rannum = System.currentTimeMillis()/1000;
        long times = System.currentTimeMillis()/1000;
        String sign = "";
        try {
            sign = generate(uid, appid, seckey,roomid, (int)times, (int)rannum);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sign ;
    }
    
    public static String generate(String uID,String appID, String appCertificate, String roomID, int unixTs, int randomInt) throws Exception {
        String unixTsStr = ("0000000000" + Integer.toString(unixTs)).substring(Integer.toString(unixTs).length());
        String randomIntStr = ("00000000" + Integer.toHexString(randomInt)).substring(Integer.toHexString(randomInt).length());
        String signature = generateSignature(uID,appID, appCertificate, roomID, unixTsStr, randomIntStr);
        return String.format("%s%s%s", signature, unixTsStr, randomIntStr);
    }

    private static String generateSignature(String uID,String appID, String appCertificate, String roomID, String unixTsStr, String randomIntStr) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(uID.getBytes());
        baos.write(appID.getBytes());
        baos.write(unixTsStr.getBytes());
        baos.write(randomIntStr.getBytes());
        baos.write(roomID.getBytes());
        byte[] sign = encodeHMAC(appCertificate, baos.toByteArray());
        return bytesToHex(sign);
    }

    static byte[] encodeHMAC(String key, byte[] message) throws NoSuchAlgorithmException, InvalidKeyException {
        return encodeHMAC(key.getBytes(), message);
    }

    static byte[] encodeHMAC(byte[] key, byte[] message) throws NoSuchAlgorithmException, InvalidKeyException {
        SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA1");

        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(keySpec);
        return mac.doFinal(message);
    }

    static String bytesToHex(byte[] in) {
        final StringBuilder builder = new StringBuilder();
        for (byte b : in) {
            builder.append(String.format("%02x", b));
        }
        return builder.toString();
    }
}

3. 申明

Token是SDK验证APP的重要参数,请注意不要明文显示、传输、保存、拷贝。