Rust Web Rokcet 系列 3 使用 JWT
系列 -
目录
注意
本文最后更新于 2024-03-05,文中内容可能已过时。
JWT即使用的包是jsonwebtoken。是使用token进行验证的一种方式。基于token
的认证方式相比传统的session
认证方式相比节约服务器资源。 JWT 官网 https://jwt.io/ 。
本次使用的包是jsonwebtoken。代码基于本系列第二篇文章 ,系列地址 https://www.ftls.xyz/series/rust-web-rokcet/
依赖
Cargo.toml 增加依赖
jsonwebtoken = "8.0.1"
代码
src\module.rs 增加代码:
#[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
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<Token> {
let split_vec = header.split_whitespace().collect::<Vec<_>>();
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<Token> {
let mut val = Validation::default();
val.sub = Some("!Yg43#xQtBE357js".to_string());
match decode::<Claims>(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<Self, Self::Error> {
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
即可。
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 = "<user_auth>")]
pub async fn get_token(user_auth: Json<UserAuth>) -> 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 增加
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 方法,
该请求的
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}}。
这之后就可以正常请求了。
本系列 Postman 分享链接:
https://www.getpostman.com/collections/c89ec512876818f18757
如果链接失效了,请只会一声。或 teach.postman_collection.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": ""
}
]
}
欢迎赞赏~
赞赏