feat: token vylepšení

This commit is contained in:
EETagent 2022-10-25 15:50:46 +02:00
parent e059719172
commit 44b4310ddf
8 changed files with 130 additions and 77 deletions

View file

@ -0,0 +1,39 @@
use config::DbConn;
use rocket::http::Status;
use rocket::outcome::Outcome;
use rocket::request::{self, FromRequest, Request};
use rocket::response::status;
use rocket_contrib::json::Json;
use portfolio_core::token::decode_candidate_token;
impl<'a, 'r> FromRequest<'a, 'r> for UserToken {
type Error = status::Custom<Json<Response>>;
fn from_request(
request: &'a Request<'r>,
) -> request::Outcome<Self, status::Custom<Json<Response>>> {
let conn = request.guard::<DbConn>().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_candidate_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(),
}),
),
))
}
}

View file

@ -4,11 +4,13 @@ version = "0.1.0"
edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
portfolio-entity = { path = "../entity" }
rand = "0.8.5"
argon2 = "0.4.1"
chrono = "0.4.22"
jsonwebtoken = "8.1.1"
dotenv = "0.15.0"
[dependencies.sea-orm]
version = "^0.10.0"

View file

@ -1,77 +0,0 @@
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<Json<Response>>;
fn from_request(
request: &'a Request<'r>,
) -> request::Outcome<Self, status::Custom<Json<Response>>> {
let conn = request.guard::<DbConn>().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<TokenData<UserToken>> {
jsonwebtoken::decode::<UserToken>(&token, &DecodingKey::from_secret(include_bytes!("secret.key")), &Validation::default())
}
fn verify_token(token_data: &TokenData<UserToken>, conn: &DbConn) -> bool {
User::is_valid_login_session(&token_data.claims, conn)
}

View file

@ -1,6 +1,7 @@
mod mutation;
mod query;
pub mod crypto;
pub mod token;
pub use mutation::*;
pub use query::*;

View file

@ -0,0 +1,9 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct AdminToken {
// issued at
pub iat: i64,
// expiration
pub exp: i64,
}

View file

@ -0,0 +1,11 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct CandidateToken {
// issued at
pub iat: i64,
// expiration
pub exp: i64,
pub name: String,
pub surname: String,
}

67
core/src/token/mod.rs Normal file
View file

@ -0,0 +1,67 @@
pub mod admin_token;
pub mod candidate_token;
use chrono::Utc;
use entity::{admin, candidate};
use jsonwebtoken::errors::Result;
use jsonwebtoken::TokenData;
use jsonwebtoken::{DecodingKey, EncodingKey};
use jsonwebtoken::{Header, Validation};
use admin_token::AdminToken;
use candidate_token::CandidateToken;
const ONE_WEEK: i64 = 60 * 60 * 24 * 7;
pub fn generate_candidate_token(candidate: candidate::Model) -> String {
let now = Utc::now().timestamp_nanos() / 1_000_000_000; // nanosecond -> second
let payload = CandidateToken {
iat: now,
exp: now + ONE_WEEK,
name: candidate.name.unwrap_or_else(|| "".into()),
surname: candidate.surname.unwrap_or_else(|| "".into()),
};
jsonwebtoken::encode(
&Header::default(),
&payload,
&EncodingKey::from_secret(include_bytes!("secret.key")),
)
.unwrap()
}
pub fn generate_admin_token(_admin: admin::Model) -> String {
let now = Utc::now().timestamp_nanos() / 1_000_000_000; // nanosecond -> second
let payload = AdminToken {
iat: now,
exp: now + ONE_WEEK,
};
jsonwebtoken::encode(
&Header::default(),
&payload,
&EncodingKey::from_secret(include_bytes!("secret.key")),
)
.unwrap()
}
pub fn decode_candidate_token(token: String) -> Result<TokenData<CandidateToken>> {
jsonwebtoken::decode::<CandidateToken>(
&token,
&DecodingKey::from_secret(include_bytes!("secret.key")),
&Validation::default(),
)
}
pub fn decode_admin_token(token: String) -> Result<TokenData<AdminToken>> {
jsonwebtoken::decode::<AdminToken>(
&token,
&DecodingKey::from_secret(include_bytes!("secret.key")),
&Validation::default(),
)
}
/*pub fn verify_token(token_data: &TokenData<UserToken>, conn: &DbConn) -> bool {
User::is_valid_login_session(&token_data.claims, conn)
}*/

View file

@ -0,0 +1 @@
temp