如何在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里的正确实现步骤:
- 解析PEM格式公钥为RSA公钥
- 提取公钥的DER编码(PKCS#1格式)
- 对DER编码做SHA256哈希
- 转换为冒号分隔的大写十六进制字符串
示例代码(依赖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) }
四、快速排查步骤
- 把你生成的JWT拆成Header、Payload、Signature三部分,对比SnowSql生成的JWT Payload字段是否一致(重点看sub、iss、iat、exp)
- 用
DESC USER <你的用户名>在SnowSql中查看RSA_PUBLIC_KEY_FINGERPRINT,和你代码生成的指纹对比 - 确保私钥无密码保护,若有密码,先用
openssl rsa -in private_key.pem -out decrypted_key.pem解密
内容的提问来源于stack exchange,提问作者Garrett Berg
相关产品推荐
相关产品推荐

