Token验证

Token格式

13003.T3.rQQzFFI7X9kjyiDEjbNnhRjXTKYjRPWerdwOkklmMXeMu1g85OHsZBtT3nxQtKknVwObtfmYoBTw_K661c5StQ

Token是一个长度小于255的字符串,中间用点(.)分隔成3个部分,依次是HeaderVersionPayload

  • Header 头部,值为渠道号
  • Version 版本号,当前版本号值为T3
  • Payload 负载,使用AES算法加密后Base64编码URLSafe的字符串

Payload内容定义

AES(channelId-userId-timestamp-channelUserId)
// 例如
AES(13003-24280710-1685709477-e7f779c82f804882ba18c5c38ed7cb4b)
  • channelId 当前登录的渠道ID
  • userId 用户ID
  • timestamp 时间戳(秒),表示token生成时间,用于校验token时效性(比如60分钟内有效)
  • channelUserId 第三方渠道的用户ID(仅供参考,游戏内可忽略)
密文 rQQzFFI7X9kjyiDEjbNnhRjXTKYjRPWerdwOkklmMXeMu1g85OHsZBtT3nxQtKknVwObtfmYoBTw_K661c5StQ
AES解密之后
明文 13003-24280710-1685709477-e7f779c82f804882ba18c5c38ed7cb4b

AES算法说明

  • AES加密模式:ECB
  • AES加密模式:PKCS5Padding
  • 密钥长度:256位
  • 密文编码:Base64 URLSafe
  • 字符编码:UTF-8
  • AES_KEY: 联系发行技术获取,不与其他密钥相同

解密工具AES Encryption and Decryption Online Toolopen in new window

Token示例

13003.T3.rQQzFFI7X9kjyiDEjbNnhRjXTKYjRPWerdwOkklmMXeMu1g85OHsZBtT3nxQtKknVwObtfmYoBTw_K661c5StQ
13108.T3.k_KWhzWMMY840voOlAH5dXd_6aERARR0F3GvQbXQd5rWPPfYv_lxmw8sxQN3OFDSCVP3qxfaBPloDbdwjKegvw
13301.T3.p98G7M7YnfCS9UxQ8vJapFEXmhXpYoPvSWK7c5wUIBOqNgBRYjUx3HTFlF5oA6aHwx7bNWa0T_CO2WSdVYztxbOIFSDm8oDp3IZn-SXmHn8
13303.T3.8befuFi8NzV9qZ9T9ATGtZxNgt4F8cPwv1XliedK0l-A0_NZR20WNatDHwhxgjzRdM78_BCdCbcK8yWe4CsqcQ
13306.T3.6rZvRXCEpXzCDXkuKkKQ2ziBVb_tYuveKWgqMIlRAYyL1DGtuBx4nlZBvmq0MHg4
13307.T3.ZyyVJtFqCtZ0dLEdUFnNtKseV8S43n2qANR_4aD_S8_V4R7Vg85JsAQDsIhERih9nDqfCM_WJBFK_8oiylN_Ew
13309.T3.ZkCLAJuGdetfcaiivsQu0Vj6gzlkmvkz3P4OLiYBFefUNE0PEXDStM6gMmaFKIT8

解密示例

解密示例

代码示例

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class TokenParser {

    private static final String AES_KEY = "联系发行技术获取";
    private static final String KEY_ALGORITHM = "AES";
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

    /**
     * 解密
     *
     * @param content 密文
     * @param key     密钥
     * @return 明文
     */
    public static String decrypt(String content, String key) {
        try {
            if (key == null) {
                System.out.println("AES key should not be null");
                return null;
            }
            byte[] data = Base64.decodeBase64(content);
            byte[] raw = key.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec keySpec = new SecretKeySpec(raw, KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] original = cipher.doFinal(data);
            return new String(original, StandardCharsets.UTF_8);
        } catch (Exception e) {
            System.out.println("解密异常error" + e.getMessage());
            return null;
        }
    }

    public static void main(String[] args) {
        String token = "13003.T3.rQQzFFI7X9kjyiDEjbNnhRjXTKYjRPWerdwOkklmMXeMu1g85OHsZBtT3nxQtKknVwObtfmYoBTw_K661c5StQ";
        String[] parts = token.split("\\.");
        String header = parts[0];
        System.out.println("header: " + header);
        String version = parts[1];
        System.out.println("version: " + version);
        String payload = parts[2];
        String result = decrypt(payload, AES_KEY);
        if (result != null) {
            //解密成功: 13003-24280710-1685709477-e7f779c82f804882ba18c5c38ed7cb4b
            //解密参数对应: channelId-userId-timestamp-channelUserId
            System.out.println("解密成功: " + result);
        } else {
            System.out.println("解密失败");
        }
    }

}
Last Updated:
Contributors: zjl