mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-21 05:18:44 +00:00
feat: get refresh token
This commit is contained in:
parent
a58cf73acc
commit
9378dcbead
5 changed files with 86 additions and 5 deletions
|
|
@ -4,6 +4,7 @@ extern crate rocket;
|
|||
use guard::candidate_jwt::TokenRequest;
|
||||
use portfolio_core::error::ServiceError;
|
||||
use portfolio_core::services::candidate_service::CandidateService;
|
||||
use portfolio_core::services::session_service::SessionService;
|
||||
use requests::LoginRequest;
|
||||
use rocket::http::Status;
|
||||
use rocket::{Rocket, Build};
|
||||
|
|
@ -45,6 +46,17 @@ async fn create(conn: Connection<'_, Db>, post_form: Json<candidate::Model>) ->
|
|||
Ok(plain_text_password)
|
||||
}
|
||||
|
||||
#[get("/refresh")]
|
||||
async fn refresh_token(conn: Connection<'_, Db>, token_req: Result<TokenRequest, Status>) -> Result<String, Custom<String>> {
|
||||
let db = conn.into_inner();
|
||||
let jwt = token_req.ok().unwrap().to_token();
|
||||
|
||||
let refresh_token = SessionService::new_refresh_token(db, jwt.application_id).await;
|
||||
|
||||
Ok(refresh_token.ok().unwrap())
|
||||
|
||||
}
|
||||
|
||||
#[post("/login", data = "<login_form>")]
|
||||
async fn login(conn: Connection<'_, Db>, login_form: Json<LoginRequest>) -> Result<String, Custom<String>> {
|
||||
let db = conn.into_inner();
|
||||
|
|
@ -72,7 +84,13 @@ async fn whoami(conn: Connection<'_, Db>, token_req: Result<TokenRequest, Status
|
|||
let user = CandidateService::authenticate_candidate(db, token).await;
|
||||
|
||||
match user {
|
||||
Ok(user) => Ok(format!("{} {}", user.name.unwrap(), user.surname.unwrap())),
|
||||
Ok(user) => Ok(
|
||||
format!("{} {} {}",
|
||||
user.application,
|
||||
user.name.unwrap_or("".to_owned()),
|
||||
user.surname.unwrap_or("".to_owned())
|
||||
)
|
||||
),
|
||||
Err(e) => Err(custom_err_from_service_err(e)),
|
||||
}
|
||||
}
|
||||
|
|
@ -94,7 +112,7 @@ async fn start() -> Result<(), rocket::Error> {
|
|||
.attach(Db::init())
|
||||
.attach(AdHoc::try_on_ignite("Migrations", run_migrations))
|
||||
//.mount("/", FileServer::from(relative!("/static")))
|
||||
.mount("/", routes![create, login, hello, whoami])
|
||||
.mount("/", routes![create, login, hello, whoami, refresh_token])
|
||||
.register("/", catchers![])
|
||||
.launch()
|
||||
.await
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use argon2::{
|
|||
Argon2, PasswordHasher as ArgonPasswordHasher, PasswordVerifier as ArgonPasswordVerifier,
|
||||
};
|
||||
use rand::Rng;
|
||||
use sha2::{Sha256, Digest};
|
||||
|
||||
|
||||
/// Foolproof random 8 char string
|
||||
|
|
@ -28,6 +29,14 @@ pub fn random_8_char_string() -> String {
|
|||
s
|
||||
}
|
||||
|
||||
pub fn hash_sha256(s: String) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(s);
|
||||
let result = hasher.finalize();
|
||||
format!("{result:x}")
|
||||
|
||||
}
|
||||
|
||||
pub fn hash_password(password_plaint_text: &str) -> Result<String, argon2::password_hash::Error> {
|
||||
let password = password_plaint_text.as_bytes();
|
||||
let salt = "c2VjcmV0bHl0ZXN0aW5nZXZlcnl0aGluZw";
|
||||
|
|
@ -51,3 +60,10 @@ pub fn verify_password(
|
|||
.verify_password(password_plaint_text.as_bytes(), &parsed_hash)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_password_test() {
|
||||
let password = "test";
|
||||
let hash = hash_password(password).unwrap();
|
||||
assert!(verify_password(password, &hash).unwrap());
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
use ::entity::{candidate};
|
||||
use sea_orm::*;
|
||||
use chrono::Utc;
|
||||
use ::entity::{candidate, session};
|
||||
use sea_orm::{*, prelude::Uuid};
|
||||
use crate::crypto::hash_password;
|
||||
|
||||
pub struct Mutation;
|
||||
|
|
@ -24,4 +25,22 @@ impl Mutation {
|
|||
.insert(db)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
pub async fn insert_session(
|
||||
db: &DbConn,
|
||||
user_id: i32,
|
||||
random_uuid: Uuid,
|
||||
hashed_jwt: String
|
||||
) -> Result<session::Model, DbErr> {
|
||||
session::ActiveModel {
|
||||
id: Set(random_uuid),
|
||||
hashed_token: Set(hashed_jwt),
|
||||
user_id: Set(user_id),
|
||||
created_at: Set(Utc::now().naive_local()),
|
||||
updated_at: Set(Utc::now().naive_local()),
|
||||
}
|
||||
.insert(db)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
pub mod candidate_service;
|
||||
pub mod candidate_service;
|
||||
pub mod session_service;
|
||||
27
core/src/services/session_service.rs
Normal file
27
core/src/services/session_service.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use sea_orm::{prelude::Uuid, DbConn};
|
||||
|
||||
use crate::{token::{generate_candidate_token}, Query, error::{USER_NOT_FOUND_ERROR, DB_ERROR, ServiceError}, crypto::hash_sha256, Mutation};
|
||||
|
||||
pub struct SessionService;
|
||||
|
||||
impl SessionService {
|
||||
pub async fn new_refresh_token(db: &DbConn, id: i32) -> Result<String, ServiceError> {
|
||||
let candidate = match Query::find_candidate_by_id(db, id).await {
|
||||
Ok(candidate) => match candidate {
|
||||
Some(candidate) => candidate,
|
||||
None => return Err(USER_NOT_FOUND_ERROR)
|
||||
},
|
||||
Err(_) => {return Err(DB_ERROR)}
|
||||
};
|
||||
let random_uuid: Uuid = Uuid::new_v4();
|
||||
|
||||
let jwt = generate_candidate_token(candidate);
|
||||
|
||||
let session = match Mutation::insert_session(db, id, random_uuid, hash_sha256(jwt)).await {
|
||||
Ok(session) => session,
|
||||
Err(_) => return Err(DB_ERROR)
|
||||
};
|
||||
|
||||
Ok(session.id.to_string())
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue