# Rust Web Rokcet 系列 3 使用 JWT JWT即使用的包是jsonwebtoken。是使用token进行验证的一种方式。基于`token`的认证方式相比传统的`session`认证方式相比节约服务器资源。 JWT 官网 https://jwt.io/ 。 本次使用的包是jsonwebtoken。代码基于本系列第二篇文章 ,系列地址 [https://www.ftls.xyz/series/rust-web-rokcet/](https://www.ftls.xyz/series/rust-web-rokcet/) ## 依赖 Cargo.toml 增加依赖 ```toml jsonwebtoken = "8.0.1" ``` ## 代码 src\module.rs 增加代码: ```rust #[derive(Deserialize, Serialize)] #[serde(crate = "rocket::serde")] pub struct Claims { pub sub: String, pub exp: u64, } #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(crate = "rocket::serde")] pub struct UserAuth { pub id: i32, pub key: String, } ``` 增加 src\auth.rs ```rust use crate::module::Claims; use jsonwebtoken::{decode, DecodingKey, Validation}; use rocket::http::Status; use rocket::request::{FromRequest, Outcome}; pub const KEY: &[u8] = b"secret"; pub struct Token; // Bearer Token impl Token { fn from_request(header: &str) -> Option { let split_vec = header.split_whitespace().collect::>(); if split_vec.len() != 2 { return None; } if split_vec[0] != "Bearer" { return None; } Self::from_jwt(split_vec[1]) } fn from_jwt(token_string: &str) -> Option { let mut val = Validation::default(); val.sub = Some("!Yg43#xQtBE357js".to_string()); match decode::(token_string, &DecodingKey::from_secret(KEY), &val) { Ok(c) => { println!("ExpTime:{:?}", c.claims.exp); return Some(Token); } Err(_) => None, } } } #[rocket::async_trait] impl<'r> FromRequest<'r> for Token { type Error = (); async fn from_request(request: &'r rocket::Request<'_>) -> Outcome { let header_auth = request.headers().get_one("Authorization"); if let Some(header_auth) = header_auth { if let Some(auth) = Self::from_request(header_auth) { return Outcome::Success(auth); } } Outcome::Failure((Status::Unauthorized, ())) } } ``` src\routes.rs 增加代码: 其他路由使用 Token 验证只需要在函数中添加变量 `_auth: Token` 即可。 ```rust use crate::auth::{Token, KEY}; use crate::module::{Claims, UserAuth}; use jsonwebtoken::{encode, EncodingKey, Header}; use std::time::{SystemTime, UNIX_EPOCH}; // get token #[post("/token", format = "json", data = "")] pub async fn get_token(user_auth: Json) -> Value { let user = user_auth.into_inner(); if user.id == 0 && user.key.eq("oR66T*W8y4VaXkh#rTjeZ$$Rby$NCy!nJX") { let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_secs(); let token = match encode( &Header::default(), &Claims { sub: String::from("!Yg43#xQtBE357js"), exp: timestamp + 5, }, &EncodingKey::from_secret(KEY), ) { Ok(t) => t, Err(_) => panic!(), }; json!({ "token": token }) } else { json!({"token": "Auth Fail"}) } } // get token test #[get("/token/test")] pub async fn get_token_test(_auth: Token) -> Value { json!({"status":"Auth Success"}) } ``` src\main.rs 增加 ```rust mod auth; #[launch] fn rocket() -> _ { rocket::build() // database .attach(MainDbConn::fairing()) .mount("/", routes![index]) // add api .mount("/", routes![get_all_articles, get_article_by_id]) .mount("/", routes![post_article, put_article]) .mount("/", routes![delete_all_articles, delete_article]) // token 本文新增的 .mount("/", routes![get_token, get_token_test]) } ``` ## 测试 测试 http://127.0.0.1:8000/token/test 方法, 该请求的 ```js const gettoken = { url: ' http://127.0.0.1:8000/token', method: "POST", header: 'Content-Type: application/json', body: { mode: 'raw', raw: JSON.stringify({"id": 0, "key": "oR66T*W8y4VaXkh#rTjeZ$$Rby$NCy!nJX"}) } } pm.sendRequest(gettoken, function (err, response) { console.log(response.json().token); pm.collectionVariables.set("token",response.json().token); }); ``` 在该请求的 Header 中添加键Authorization ,值 Bearer {{token}}。 {{< image src="https://cdn.ftls.xyz/images/2022/02/20220216132819.png" caption="Postman测试" >}} 这之后就可以正常请求了。 本系列 Postman 分享链接: https://www.getpostman.com/collections/c89ec512876818f18757 如果链接失效了,请只会一声。或 teach.postman_collection.json 如下 ```json { "info": { "_postman_id": "709bf03a-bdd4-4b98-afac-b01ae46d2b65", "name": "teach", "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", "_exporter_id": "16599952" }, "item": [ { "name": "http://127.0.0.1:8000/", "request": { "method": "GET", "header": [], "url": "http://127.0.0.1:8000/" }, "response": [] }, { "name": "获取所有文章", "request": { "method": "GET", "header": [], "url": "http://127.0.0.1:8000/article" }, "response": [] }, { "name": "增加文章", "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "{\r\n \"title\": \"a title\",\r\n \"author\": \"恐咖兵糖\",\r\n \"content\": \"dasdaadas\",\r\n \"created_at\": \"2022-02-14 \"\r\n}", "options": { "raw": { "language": "json" } } }, "url": "http://127.0.0.1:8000/article" }, "response": [] }, { "name": "获取文章 by id", "request": { "method": "GET", "header": [], "url": "http://127.0.0.1:8000/article/2" }, "response": [] }, { "name": "删除文章 by id", "request": { "method": "DELETE", "header": [], "url": "http://127.0.0.1:8000/article/3" }, "response": [] }, { "name": "更新文章", "request": { "method": "PUT", "header": [], "body": { "mode": "raw", "raw": "{\r\n \"title\": \"a title\",\r\n \"author\": \"恐咖兵糖\",\r\n \"content\": \"222ssss2\",\r\n \"created_at\": \"2022-02-14 \"\r\n}", "options": { "raw": { "language": "json" } } }, "url": "http://127.0.0.1:8000/article/4" }, "response": [] }, { "name": "删除所有文章", "request": { "method": "DELETE", "header": [], "url": "http://127.0.0.1:8000/article/all" }, "response": [] }, { "name": "获取token", "request": { "method": "POST", "header": [], "body": { "mode": "raw", "raw": "{\r\n \"id\": 0,\r\n \"key\": \"oR66T*W8y4VaXkh#rTjeZ$$Rby$NCy!nJX\"\r\n}", "options": { "raw": { "language": "json" } } }, "url": "http://127.0.0.1:8000/token" }, "response": [] }, { "name": "token 测试", "event": [ { "listen": "prerequest", "script": { "exec": [ "const gettoken = {\r", " url: ' http://127.0.0.1:8000/token',\r", " method: \"POST\",\r", " header: 'Content-Type: application/json',\r", " body: {\r", " mode: 'raw', \r", " raw: JSON.stringify({\"id\": 0, \"key\": \"oR66T*W8y4VaXkh#rTjeZ$$Rby$NCy!nJX\"}) //要将JSON对象转为文本发送\r", "\r", " }\r", "}\r", "pm.sendRequest(gettoken, function (err, response) {\r", " console.log(response.json().token);\r", " pm.collectionVariables.set(\"token\",response.json().token);\r", "});" ], "type": "text/javascript" } } ], "request": { "method": "GET", "header": [ { "key": "Authorization", "value": "Bearer {{token}}", "type": "default" } ], "url": "http://127.0.0.1:8000/token/test" }, "response": [] } ], "variable": [ { "key": "token", "value": "" } ] } ```