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 在傳輸中洩漏

相關文件