You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中正确生成JWT以连接Snowflake实例

Rust生成Snowflake有效JWT的问题排查与解决

报错390144核心原因

这个错误是Snowflake验证JWT签名失败,问题集中在三个点:sub字段格式错误、公钥指纹生成不正确、JWT签名算法/密钥使用错误。

一、sub字段的正确设置

Snowflake要求sub字段必须是<用户名>.<账户短名>格式:

  • 账户短名是你Snowflake账户的标识符(不带区域、云服务商后缀),比如账户是xy123.us-west-2.aws,那账户短名就是xy123
  • 示例:用户名为john_doe,账户短名xy123,则sub为john_doe.xy123
  • 不要用完整账户URL,不要加多余字符,严格按上述格式

二、公钥指纹的正确生成(对齐Python实现)

Snowflake需要的是公钥的SHA256指纹,格式为冒号分隔的大写十六进制字符串(比如A1:B2:C3:DD:...)。Rust里的正确实现步骤:

  1. 解析PEM格式公钥为RSA公钥
  2. 提取公钥的DER编码(PKCS#1格式)
  3. 对DER编码做SHA256哈希
  4. 转换为冒号分隔的大写十六进制字符串

示例代码(依赖openssl和sha2 crate):

use openssl::pkey::PKey;
use openssl::rsa::Rsa;
use sha2::{Sha256, Digest};

fn generate_fingerprint(public_key_pem: &str) -> String {
    // 解析PEM公钥
    let rsa = Rsa::public_key_from_pem(public_key_pem.as_bytes()).expect("Failed to parse public key");
    let pkey = PKey::from_rsa(rsa).expect("Failed to convert RSA to PKey");
    // 获取DER编码
    let der = pkey.public_key_to_der().expect("Failed to get DER encoding");
    // 计算SHA256哈希
    let mut hasher = Sha256::new();
    hasher.update(&der);
    let hash_result = hasher.finalize();
    // 转换为冒号分隔的大写十六进制
    hash_result.iter()
        .map(|byte| format!("{:02X}", byte))
        .collect::<Vec<_>>()
        .join(":")
}

三、encoding_key与encode函数的正确使用

Snowflake JWT必须用RS256算法,签名用RSA私钥,注意私钥格式(PKCS#1或PKCS#8均支持,若有密码需先解密)。用jsonwebtoken crate的示例代码:

use jsonwebtoken::{encode, Header, Algorithm, EncodingKey, Claims};
use serde::{Serialize, Deserialize};
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug, Serialize, Deserialize)]
struct SnowflakeClaims {
    sub: String,
    iss: String,
    iat: u64,
    exp: u64,
}

fn generate_snowflake_jwt(
    username: &str,
    account_short_name: &str,
    private_key_pem: &str
) -> Result<String, jsonwebtoken::errors::Error> {
    let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
    let claims = SnowflakeClaims {
        sub: format!("{}.{}", username, account_short_name),
        iss: format!("{}.{}", account_short_name, username), // 与sub顺序相反
        iat: now,
        exp: now + 3600, // 过期时间最多1小时,Snowflake限制
    };

    let encoding_key = EncodingKey::from_rsa_pem(private_key_pem.as_bytes())?;
    encode(&Header::new(Algorithm::RS256), &claims, &encoding_key)
}

四、快速排查步骤

  1. 把你生成的JWT拆成Header、Payload、Signature三部分,对比SnowSql生成的JWT Payload字段是否一致(重点看sub、iss、iat、exp)
  2. 用DESC USER <你的用户名>在SnowSql中查看RSA_PUBLIC_KEY_FINGERPRINT,和你代码生成的指纹对比
  3. 确保私钥无密码保护,若有密码,先用openssl rsa -in private_key.pem -out decrypted_key.pem解密

内容的提问来源于stack exchange,提问作者Garrett Berg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:35:32