mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-20 15:01:19 +00:00
feat: token vylepšení
This commit is contained in:
parent
e059719172
commit
44b4310ddf
8 changed files with 130 additions and 77 deletions
39
api/src/guard/candidate_jwt.rs
Normal file
39
api/src/guard/candidate_jwt.rs
Normal 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(),
|
||||
}),
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
mod mutation;
|
||||
mod query;
|
||||
pub mod crypto;
|
||||
pub mod token;
|
||||
|
||||
pub use mutation::*;
|
||||
pub use query::*;
|
||||
|
|
|
|||
9
core/src/token/admin_token.rs
Normal file
9
core/src/token/admin_token.rs
Normal 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,
|
||||
}
|
||||
11
core/src/token/candidate_token.rs
Normal file
11
core/src/token/candidate_token.rs
Normal 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
67
core/src/token/mod.rs
Normal 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)
|
||||
}*/
|
||||
1
core/src/token/secret.key
Normal file
1
core/src/token/secret.key
Normal file
|
|
@ -0,0 +1 @@
|
|||
temp
|
||||
Loading…
Reference in a new issue