✨重磅!盹猫的个人小站正式上线啦~诚邀各位技术大佬前来探秘!✨
这里有:
- 硬核技术干货:编程技巧、开发经验、踩坑指南,带你解锁技术新姿势!
- 趣味开发日常:代码背后的脑洞故事、工具测评,让技术圈不再枯燥~
- 独家资源分享:开源项目、学习资料包,助你打怪升级快人一步!
👉 点击直达→ 盹猫猫的个人小站 👈
🌟 来逛逛吧,说不定能挖到你正在找的技术宝藏哦~
目录
Welcome to Code Block's blog
本篇文章主要介绍了
[Rocket框架JWT鉴权实战:保护Rust Web API的安全方案]
❤博主广交技术好友,喜欢文章的可以关注一下❤
一、概述
本篇文章是基于rust语言和rocket依赖实现网页JWT认证和鉴权,完成简单的JWT token的验证和鉴权处理,使用cargo做依赖的导入和测试。
什么是rocket?
Rust Rocket 是一个基于 Rust 编程语言的 Web 框架,用于构建高性能、安全的 Web 应用程序。Rocket 以其简洁的语法、强大的类型系统和易用性而闻名,特别适合那些希望利用 Rust 的内存安全性和并发性能来开发 Web 服务的开发者。
二、相关依赖
Cargo.toml
[package] name = "webapp" version = "0.1.0" edition = "2024" [dependencies] chrono = "0.4.40" dotenv = "0.15.0" jsonwebtoken = "9.3.1" rocket = { version = "0.5.1", features = ["json"] } serde = { version = "1.0.219", features = ["derive"] }
chrono:一个 Rust 的日期和时间处理库,提供了丰富的时间和日期操作功能,类似于其他编程语言中的 java.time 或 Python 的 datetime 模块。
dotenv:一个用于加载环境变量的库,允许开发者将配置参数存储在 .env 文件中,从而简化配置管理和环境设置。
jsonwebtoken:一个用于生成和验证 JSON Web Token (JWT) 的库。JWT 常用于身份验证和授权,允许在不同服务之间安全地传输信息。
rocket:一个现代、快速且易于使用的 Rust Web 框架,旨在利用 Rust 的类型系统和并发能力,提供高性能的 Web 服务。
serde:一个用于序列化和反序列化数据的框架,支持多种数据格式(如 JSON、YAML、TOML 等)。它通过派生宏简化了序列化代码的编写。
通过上述依赖可以看出,Rust在Web方面的生态建设也是十分全面的,相关的依赖也比较完善。
三、环境准备
3.1 创建项目
使用cargo创建一个名为webapp项目,使用以下命令进行创建:
cargo init webapp //创建项目 cd webapp //移动到目录内
在wabapp文件夹内依次运行以下命令进行安装(或将Cargo.toml文件内数据复制到文件夹的Cargo.toml文件内),使用cargo install进行安装。
cargo add chrono cargo add dotenv cargo add jsonwebtoken cargo add rocket cargo add serde
在文件夹内创建一个 .env文件,用于存储JWT的私钥信息,并在.env文件内添加以下内容:
JWT_SECRET = 123456
3.2 读取私钥信息
使用以下代码读取私钥信息,这里用到了dotenv库:
// 从环境变量中获取密钥 fn get_secret() -> String { dotenv().ok(); env::var("JWT_SECRET").expect("JWT_SECRET must be set") }
3.3 token数据负载
这里先创建一个Claims用于存储生成和解析完成后的Token信息,其代码如下:
use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, // 主题,通常是用户ID pub exp: usize, // 过期时间,UNIX 时间戳 //根据需要添加其它字段 }
sub:用于存储用户数据,通常是用户的ID。
exp:过期时间,即token多长时间后失效。
这里用到了serde依赖,用于序列化和反序列化数据。
3.4 生成token
通过用户id和过期时间生成token字符串(其中获取过期时间时使用了chrono依赖),通过初始化claims数据,获取的私钥和头部信息,生成token字符串(生成时使用的是jsonwebtoken依赖的encode方法)。具体方法实现如下:
/// 生成 JWT pub fn create_jwt( user_id: &str, expiration_minutes: usize, ) -> Result<String, jsonwebtoken::errors::Error> { //获取过期的时间戳 let expiration = Utc::now() .checked_add_signed(Duration::minutes(expiration_minutes as i64)) .expect("valid timestamp") .timestamp(); //初始化claims数据 let claims = Claims { sub: user_id.to_owned(), exp: expiration as usize, }; //获取私钥数据 let secret = get_secret(); //jwt的头部信息(加密算法) let header = Header::default(); //进行生成并返回 encode(&header, &claims, &EncodingKey::from_secret(secret.as_ref())) }
四、Web鉴权
4.1 验证载体
这里先创建一个验证通过后的载体JwtGuard,内容如下:
#[derive(Debug, Serialize)] #[serde(crate = "rocket::serde")] pub struct JwtGuard { pub claims: Claims, // 验证通过后,存储解析的 Claims }
因为rocket是通过一个FromRequest进行拦截Request请求, 所有让JwtGuard去实现FromRequest,实现其中的from_request请求,内容如下:
#[rocket::async_trait] impl<'r> FromRequest<'r> for JwtGuard { type Error = String; async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { // 1. 从 Header 获取 Token let token = match request.headers().get_one("token") { Some(t) => t, None => return Outcome::Error((Status::Unauthorized, "Missing token".to_string())), }; // 2. 从环境变量获取 JWT_SECRET let secret = get_secret(); // 3. 验证 Token match decode::<Claims>( token, &DecodingKey::from_secret(secret.as_ref()), &Validation::new(Algorithm::HS256), //生成时的加密方法 ) { Ok(token_data) => Outcome::Success(JwtGuard { claims: token_data.claims, }), Err(e) => Outcome::Error((Status::Unauthorized, format!("Invalid token: {}", e))), } } }
普遍的方法是从请求头中获取token,从环境变量中获取私钥 ,通过jsonwebtoken依赖中的decode方法对token进行验证,成功后使用Outcome::Success()将JwtGuard传递出去(就是通过验证),错误则提示Unauthorized。
4.2 接收请求
在main.rs中可以使用如下方法接收请求:
mod jwt; #[macro_use] extern crate rocket; use jwt::{JwtGuard, create_jwt}; use rocket::serde::json::Json; #[get("/jwt")] fn login_token(_jwt: JwtGuard) -> String { //模拟用户登陆获取jwt token请求 let token = create_jwt("1122", 1).unwrap(); token } #[get("/check")] fn check_token(_jwt: JwtGuard) -> Json<JwtGuard> { //模拟用户通过验证请求 Json(_jwt) } #[launch] fn rocket() -> _ { //注册到路径 rocket::build().mount("/", routes![login_token, check_token]) }
注意:这里_jwt: JwtGuard已经被实现,所以当参数有JwtGuard时,表示该请求路径要求被认证,如果不添加,则表示该方法不需被认证,这样就实现了白名单的功能。
五、总结
通过cargo去实现web验证,可以看出,rocket在web鉴权功能实现时,要求代码简洁、易实现,各种注解的支持也非常的多。同时,同时由于Rust语言本身的特性,在实际的处理速度方面也有着不错的表现。
如果你对区块链内容感兴趣可以查看我的专栏:小试牛刀-区块链
感谢您的关注和收藏!!!!!!
编辑