From e059719172642007dd4cc226d58184d3dda88717 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Tue, 25 Oct 2022 14:52:18 +0200 Subject: [PATCH] feat: gen, decode, verify jwt --- core/src/jwt.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 core/src/jwt.rs diff --git a/core/src/jwt.rs b/core/src/jwt.rs new file mode 100644 index 0000000..2b6675e --- /dev/null +++ b/core/src/jwt.rs @@ -0,0 +1,77 @@ +use chrono::Utc; +use config::DbConn; +use jsonwebtoken::errors::Result; +use jsonwebtoken::TokenData; +use jsonwebtoken::{Header, Validation}; +use jsonwebtoken::{EncodingKey, DecodingKey}; +use models::response::Response; +use models::user::{ User, LoginInfoDTO }; +use rocket::http::Status; +use rocket::outcome::Outcome; +use rocket::request::{self, FromRequest, Request}; +use rocket::response::status; +use rocket_contrib::json::Json; + +static ONE_WEEK: i64 = 60 * 60 * 24 * 7; // in seconds + +#[derive(Debug, Serialize, Deserialize)] +pub struct UserToken { + // issued at + pub iat: i64, + // expiration + pub exp: i64, + // data + pub user: String, + pub login_session: String, +} + +impl<'a, 'r> FromRequest<'a, 'r> for UserToken { + type Error = status::Custom>; + fn from_request( + request: &'a Request<'r>, + ) -> request::Outcome>> { + let conn = request.guard::().unwrap(); + if let Some(authen_header) = request.headers().get_one("Authorization") { + let authen_str = authen_header.to_string(); + if authen_str.starts_with("Bearer") { + let token = authen_str[6..authen_str.len()].trim(); + if let Ok(token_data) = decode_token(token.to_string()) { + if verify_token(&token_data, &conn) { + return Outcome::Success(token_data.claims); + } + } + } + } + + Outcome::Failure(( + Status::BadRequest, + status::Custom( + Status::Unauthorized, + Json(Response { + message: String::from("Invalid token"), + data: serde_json::to_value("").unwrap(), + }), + ), + )) + } +} + +pub fn generate_token(login: LoginInfoDTO) -> String { + let now = Utc::now().timestamp_nanos() / 1_000_000_000; // nanosecond -> second + let payload = UserToken { + iat: now, + exp: now + ONE_WEEK, + user: login.username, + login_session: login.login_session, + }; + + jsonwebtoken::encode(&Header::default(), &payload, &EncodingKey::from_secret(include_bytes!("secret.key"))).unwrap() +} + +fn decode_token(token: String) -> Result> { + jsonwebtoken::decode::(&token, &DecodingKey::from_secret(include_bytes!("secret.key")), &Validation::default()) +} + +fn verify_token(token_data: &TokenData, conn: &DbConn) -> bool { + User::is_valid_login_session(&token_data.claims, conn) +} \ No newline at end of file