logo
开发者文档
搜索
AiToken 加密与签发

AiToken 加密与签发

概述

AiToken 是工作空间集成的核心凭证 —— 它封装了组织 ID员工账号邮箱,通过 RSA 公钥加密后拼接成专属登录 URL,让企业员工在移动端 APP 中免登录打开工作空间。


获取公钥

  1. 打开 Web 端 → 空间管理高级设置品牌集成
  2. 在集成区域找到 公钥,点击查看或复制
  3. 如需刷新密钥(不常见,会导致所有已签发 Token 失效),点击重置

以企业员工身份加密 AiToken

流程概览

步骤 1: 成员邮箱 ─── RSA 加密(公钥)───► emailEncrypted 字节 步骤 2: emailEncrypted ─── Base64 编码 ───► emailRSAStr 步骤 3: {projectId}:{emailRSAStr} 字符串拼接 步骤 4: 拼接后的字符串 ─── Base64 编码 ───► 最终 AiToken
                      
                      步骤 1: 成员邮箱 ─── RSA 加密(公钥)───► emailEncrypted 字节
步骤 2: emailEncrypted ─── Base64 编码 ───► emailRSAStr
步骤 3: {projectId}:{emailRSAStr} 字符串拼接
步骤 4: 拼接后的字符串 ─── Base64 编码 ───► 最终 AiToken

                    
此代码块在浮窗中显示

算法参数

参数
RSA 算法 RSA/ECB/PKCS1Padding(即 RSAES-PKCS1-V1_5
公钥格式 X.509(SubjectPublicKeyInfo),Base64 编码
输出编码 两次 Base64

Java 加密代码示例

import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import javax.crypto.Cipher; public class Main { private static final String RSA_ALGORITHM = "RSA"; private static final String RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding"; /** * Encrypts data using RSA public key. * * @param data The data to encrypt. * @param publicKeyStr The Base64 encoded RSA public key. * @return Encrypted data bytes. */ public static byte[] encrypt(byte[] data, String publicKeyStr) throws Exception { byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PublicKey publicKey = keyFactory.generatePublic(keySpec); Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * Generates a login key by encrypting the email and combining with projectId. * * @param projectId The project ID. * @param email The user's email. * @param publicKey The Base64 encoded RSA public key. * @return The final login key string. * @throws Exception if encryption fails. */ public static String generateLoginKey(String projectId, String email, String publicKey) throws Exception { byte[] emailEncrypted = encrypt(email.getBytes(StandardCharsets.UTF_8), publicKey); String emailRSAStr = Base64.getEncoder().encodeToString(emailEncrypted); String keyStr = projectId + ":" + emailRSAStr; return Base64.getEncoder().encodeToString(keyStr.getBytes(StandardCharsets.UTF_8)); } public static void main(String[] args) { String projectId = "your project ID"; String email = "your email"; String publicKey = "your public key"; try { String key = generateLoginKey(projectId, email, publicKey); System.out.println(key); } catch (Exception e) { System.err.println("Failed to generate login key: " + e.getMessage()); } } }
                      
                      import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;

public class Main {

    private static final String RSA_ALGORITHM = "RSA";
    private static final String RSA_TRANSFORMATION = "RSA/ECB/PKCS1Padding";

    /**
     * Encrypts data using RSA public key.
     *
     * @param data         The data to encrypt.
     * @param publicKeyStr The Base64 encoded RSA public key.
     * @return Encrypted data bytes.
     */
    public static byte[] encrypt(byte[] data, String publicKeyStr) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        Cipher cipher = Cipher.getInstance(RSA_TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * Generates a login key by encrypting the email and combining with projectId.
     *
     * @param projectId The project ID.
     * @param email     The user's email.
     * @param publicKey The Base64 encoded RSA public key.
     * @return The final login key string.
     * @throws Exception if encryption fails.
     */
    public static String generateLoginKey(String projectId, String email, String publicKey) throws Exception {
        byte[] emailEncrypted = encrypt(email.getBytes(StandardCharsets.UTF_8), publicKey);
        String emailRSAStr = Base64.getEncoder().encodeToString(emailEncrypted);
        String keyStr = projectId + ":" + emailRSAStr;
        return Base64.getEncoder().encodeToString(keyStr.getBytes(StandardCharsets.UTF_8));
    }

    public static void main(String[] args) {
        String projectId = "your project ID";
        String email = "your email";
        String publicKey = "your public key";

        try {
            String key = generateLoginKey(projectId, email, publicKey);
            System.out.println(key);
        } catch (Exception e) {
            System.err.println("Failed to generate login key: " + e.getMessage());
        }
    }
}

                    
此代码块在浮窗中显示

TypeScript 加密代码示例

import * as forge from 'node-forge'; /** * Encrypt data using RSA public key * @param data Data to be encrypted * @param publicKeyStr Base64 encoded public key string * @returns Encrypted byte array */ export function encrypt(data: string, publicKeyStr: string): Uint8Array { try { // Decode Base64 public key const publicKeyBytes = forge.util.decode64(publicKeyStr); // Create public key object const publicKey = forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyBytes)); // Use RSA encryption with PKCS1 padding (consistent with Java's default behavior) const encrypted = publicKey.encrypt(data, 'RSAES-PKCS1-V1_5'); // Convert forge's byte string to Uint8Array const bytes = new Uint8Array(encrypted.length); for (let i = 0; i < encrypted.length; i++) { bytes[i] = encrypted.charCodeAt(i) & 0xff; } return bytes; } catch (error) { throw new Error(`RSA encryption failed: ${error}`); } } /** * Convert byte array to Base64 string * @param bytes Byte array * @returns Base64 encoded string */ export function bytesToBase64(bytes: Uint8Array): string { // Convert Uint8Array to string, then use forge's encode64 const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join(''); return forge.util.encode64(binaryString); } /** * Convert string to Base64 * @param str String to be encoded * @returns Base64 encoded string */ export function stringToBase64(str: string): string { return forge.util.encode64(str); } /** * Main function - Generate encrypted key string * @param projectId Project ID * @param email Email address * @param publicKey Base64 encoded RSA public key * @returns Final encrypted Base64 string */ export function generateEncryptedKey(projectId: string, email: string, publicKey: string): string { // Use RSA to encrypt email const emailRSAEncrypt = encrypt(email, publicKey); // Convert encryption result to Base64 const emailRSAStr = bytesToBase64(emailRSAEncrypt); // Combine projectId and encrypted email const keyStr = `${projectId}:${emailRSAStr}`; // Encode the entire string with Base64 const result = stringToBase64(keyStr); return result; } // Generate AiToken example // generateEncryptedKey(projectId, email, publicKey)
                      
                      import * as forge from 'node-forge';

/**
 * Encrypt data using RSA public key
 * @param data Data to be encrypted
 * @param publicKeyStr Base64 encoded public key string
 * @returns Encrypted byte array
 */
export function encrypt(data: string, publicKeyStr: string): Uint8Array {
  try {
    // Decode Base64 public key
    const publicKeyBytes = forge.util.decode64(publicKeyStr);

    // Create public key object
    const publicKey = forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyBytes));

    // Use RSA encryption with PKCS1 padding (consistent with Java's default behavior)
    const encrypted = publicKey.encrypt(data, 'RSAES-PKCS1-V1_5');

    // Convert forge's byte string to Uint8Array
    const bytes = new Uint8Array(encrypted.length);
    for (let i = 0; i < encrypted.length; i++) {
      bytes[i] = encrypted.charCodeAt(i) & 0xff;
    }
    return bytes;
  } catch (error) {
    throw new Error(`RSA encryption failed: ${error}`);
  }
}

/**
 * Convert byte array to Base64 string
 * @param bytes Byte array
 * @returns Base64 encoded string
 */
export function bytesToBase64(bytes: Uint8Array): string {
  // Convert Uint8Array to string, then use forge's encode64
  const binaryString = Array.from(bytes, byte => String.fromCharCode(byte)).join('');
  return forge.util.encode64(binaryString);
}

/**
 * Convert string to Base64
 * @param str String to be encoded
 * @returns Base64 encoded string
 */
export function stringToBase64(str: string): string {
  return forge.util.encode64(str);
}

/**
 * Main function - Generate encrypted key string
 * @param projectId Project ID
 * @param email Email address
 * @param publicKey Base64 encoded RSA public key
 * @returns Final encrypted Base64 string
 */
export function generateEncryptedKey(projectId: string, email: string, publicKey: string): string {
  // Use RSA to encrypt email
  const emailRSAEncrypt = encrypt(email, publicKey);

  // Convert encryption result to Base64
  const emailRSAStr = bytesToBase64(emailRSAEncrypt);

  // Combine projectId and encrypted email
  const keyStr = `${projectId}:${emailRSAStr}`;

  // Encode the entire string with Base64
  const result = stringToBase64(keyStr);

  return result;
}

// Generate AiToken example
// generateEncryptedKey(projectId, email, publicKey)

                    
此代码块在浮窗中显示

生成专属登录 URL

按照 {工作空间集成URL}?{AiToken} 的格式生成员工账号专属登录 URL:

https://gptbots.ai/space/h5/home?AiToken={加密AiToken}&hideClose=true
                      
                      https://gptbots.ai/space/h5/home?AiToken={加密AiToken}&hideClose=true

                    
此代码块在浮窗中显示

企业员工在移动端 APP 中打开专属员工账号邮箱的专属加密登录 URL,即可免登录打开对应的工作空间。


安全注意事项

注意点 说明
公钥安全 公钥可以公开分发,但签发过程应在服务端完成,避免客户端直接持有项目 ID
Token 时效 AiToken 不具备有效期概念,建议签发时通过后端下发,APP 端不长期缓存
邮箱匹配 AiToken 中的邮箱必须是工作空间已存在的成员邮箱,否则会提示用户不存在
组织绑定 同一个项目 ID(projectId)对应一个组织,成员必须属于该组织
HTTPS 集成 URL 必须通过 HTTPS 访问,防止 Token 在传输中泄露

相关文档