news 2026/4/25 6:43:50

rust语言jwt生成、验证(全代码逐行注释)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
rust语言jwt生成、验证(全代码逐行注释)

JWTJSON Web Token)由三部分组成:‌Header(头部)‌、‌Payload(负载)‌ 和 ‌Signature`(签名)‌,三者通过点号 . 连接。 ‌

  • Header‌:包含令牌类型(typ: JWT)和签名算法(如alg: HS256)。
  • Payload‌:携带声明信息,包括标准字段(如 sub 用户主题、exp 过期时间、iat 签发时间)和自定义数据(如用户角色、权限等)。 ‌
  • Signature‌:使用密钥对base64UrlEncode(header) + "." + base64UrlEncode(payload)进行签名,确保数据完整性。

客户端与服务器端交互流程

客户端服务器端客户端服务器端生成密钥保存密钥登录(用户名 + 密码)验证用户信息登录失败登录成功生成 Token返回 Token保存 Token请求时带上 Token验证 Token验证失败(返回 错误)验证成功(返回 相应数据)

Cargo.toml

[dependencies] # 序列化/反序列化 serde = { version = "1.0", features = ["derive"] } # JWT 处理库 jsonwebtoken = { version = "10.3", features = ["rust_crypto"] } # 环境变量管理 dotenv = "0.15" # 日期时间处理 chrono = "0.4" # 随机数生成 rand = "0.10" # Base64 编码解码 base64 = "0.22"

导入库

usebase64::engine::general_purpose;usebase64::engine::general_purpose::STANDARD;usebase64::prelude::BASE64_STANDARD;usebase64::Engineas_;usechrono::{Duration,Utc};usedotenv::dotenv;usejsonwebtoken::{decode,encode,Algorithm,DecodingKey,EncodingKey,Header,TokenData,Validation,};useserde::{Deserialize,Serialize};usestd::collections::HashSet;usestd::env;usestd::fs;usestd::io::Write;

JWT载荷结构体

/// 定义JWT载荷结构体#[derive(Debug, Serialize, Deserialize)]pubstructClaims{pubsub:String,// 用户标识(subject)pubexp:i64,// 过期时间(expiration)pubiat:i64,// 签发时间pubiss:String,// 签发者(issuer)pubroles:Vec<String>,// 角色权限}implClaims{pubfnnew(sub:String,iss:String,roles:Vec<String>)->Self{letnow=Utc::now().timestamp();letexp=now+3600;// 单位秒。1小时后过期,或 + Duration::hours(1);Self{sub,exp,iat:now,iss,roles,}}}

生成密钥

/// 生成随机密钥并保存到文件pubfngenerate_and_save_key()->Result<(),jsonwebtoken::errors::Error>{// 生成32字节的随机密钥(用于HS256算法)letkey=(0..32).map(|_|rand::random::<u8>()).collect::<Vec<u8>>();// 将密钥保存为base64编码的字符串letkey_base64=STANDARD.encode(&key);// 写入到文件letmutfile=std::fs::File::create("jwt_secret.key").unwrap();writeln!(file,"{}",key_base64).unwrap();println!("密钥已生成并保存到 jwt_secret.key 文件");Ok(())}

读取密钥

/// 从文件读取密钥pubfnload_secret_key()->Result<Vec<u8>,jsonwebtoken::errors::Error>{// 加载环境变量dotenv().ok();// 优先从环境变量读取密钥ifletOk(secret_env)=env::var("JWT_SECRET"){returnOk(STANDARD.decode(&secret_env)?);}// 如果环境变量不存在,从文件读取letkey_content=fs::read_to_string("jwt_secret.key").unwrap();letkey_base64=key_content.trim();letkey=STANDARD.decode(key_base64)?;Ok(key)}

生成 JWT 令牌

/// 生成JWT令牌pubfngenerate_token(claims:&Claims)->Result<String,jsonwebtoken::errors::Error>{// 加载密钥letsecret=load_secret_key()?;// 创建JWT头部letheader=Header::default();// 使用HS256算法和密钥生成JWT令牌// JWT头部 + JWT载荷 + 加密密钥lettoken=encode(&header,&claims,&EncodingKey::from_secret(&secret))?;Ok(token)}

验证 JWT

/// 验证JWT令牌pubfnvalidate_token(token:&str)->Result<TokenData<Claims>,jsonwebtoken::errors::Error>{// 加载密钥letsecret=load_secret_key()?;// 配置验证参数letmutvalidation=Validation::new(Algorithm::HS256);validation.leeway=60;// 允许时钟偏差,秒validation.validate_exp=true;// 是否验证 "过期时间" 字段。 如果exp字段中的时间已过,它将返回一个错误。validation.validate_nbf=false;// 是否验证 "生效时间" 字段。早于生效时间报错validation.iss=Some(HashSet::from(["xtsz".to_string()]));// 签发者(issuer)// 解码并验证JWT令牌// JWT令牌 + 解密密钥 + 验证参数lettoken_data=decode::<Claims>(token,&DecodingKey::from_secret(&secret),&validation)?;

测试

#[cfg(test)]// 表示以下模块仅在测试模式下编译modtests{// 定义测试模块usesuper::*;usejsonwebtoken::errors::ErrorKind;// 导入父模块中的所有内容#[test]fntest_1()->Result<(),jsonwebtoken::errors::Error>{// 1. 生成并保存密钥(仅首次运行时需要)generate_and_save_key()?;// 2. 生成JWT令牌letclaims=Claims::new("user123".to_string(),// 用户标识"xtsz".to_string(),// 签发者标识vec!["s".to_string()],// 用户权限);lettoken=generate_token(&claims)?;// 生成JWT令牌println!("生成的令牌: {}",token);// 3. 验证JWT令牌lettoken_result=validate_token(&token);// let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIiwiZXhwIjoxNzc2NzYzMzQwLCJpYXQiOjE3NzY3NjMzMzUsImlzcyI6Inh0c3oiLCJyb2xlcyI6WyJzIl19.oh3xI_u_op-WkdiV77jQ5JF0p0HUqY0_sxhaZXI3eio";// let token_result = validate_token(token);// 获取验证信息matchtoken_result{// 令牌正确Ok(token_data)=>{println!("令牌验证成功,用户: {}",token_data.claims.sub);println!("服务器: {}",token_data.claims.iss);lettime1=Utc::now().timestamp();lettime2=token_data.claims.exp;lettime3=time2-time1;println!("当前时间:{}",time1);println!("过期时间: {}",time2);println!("距离过期还有: {}秒",time3);println!("签发时间:{}",token_data.claims.iat);println!("角色权限:{}",token_data.claims.roles.get(0).unwrap());}// 令牌错误Err(err)=>{matcherr.kind(){ErrorKind::ExpiredSignature=>{eprintln!("Token 过期");}ErrorKind::InvalidIssuer=>{eprintln!("发行方无效");}ErrorKind::InvalidSignature=>{eprintln!("无效签名");}_=>{eprintln!("其他错误: {:?}",err);}}}}Ok(())}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 6:33:21

3步完成Tabletop Simulator数据保护:TTS-Backup终极指南

3步完成Tabletop Simulator数据保护&#xff1a;TTS-Backup终极指南 【免费下载链接】tts-backup Backup Tabletop Simulator saves and assets into comprehensive Zip files. 项目地址: https://gitcode.com/gh_mirrors/tt/tts-backup 在桌游模拟器(Tabletop Simulato…

作者头像 李华
网站建设 2026/4/25 6:18:55

浦语灵笔2.5-7B高算力适配:双卡44GB显存下batch_size=2实测

浦语灵笔2.5-7B高算力适配&#xff1a;双卡44GB显存下batch_size2实测 今天我们来聊聊一个非常实际的问题&#xff1a;当你手头有两张RTX 4090D&#xff08;总共44GB显存&#xff09;&#xff0c;想跑一个21GB的视觉语言大模型时&#xff0c;到底能撑起多大的并发量&#xff1…

作者头像 李华
网站建设 2026/4/25 6:15:51

同一事务内数据不一致问题复盘

同一事务内数据不一致问题复盘 一、问题背景 在活动初始化任务中&#xff0c;系统需要批量写入商品范围、渠道范围以及规则明细&#xff0c;并在初始化完成后继续执行衍生数据计算和状态更新。 这类链路步骤长、涉及表多、写入量大&#xff0c;对事务一致性和异常传播要求很高。…

作者头像 李华
网站建设 2026/4/25 6:09:23

支持多协议转换的工业物联网智能网关应用

工业级4G远程双卡双待物联网智能网关 型号&#xff1a;JM-WG310-IOT22 第 1 章 产品简介 1.1 产品概述 JM-WG310-IOT22 是基于 5G/4G/3G/2G 、WiFi 、虚拟专网等技术开发的工业级路由器/CPE 。产品采用高性能的工业级 32 位通信处理器和工业级无线模块&#xff0c;以嵌入式…

作者头像 李华