mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-18 22:11:14 +00:00
feat: session authentication instead of jwt
This commit is contained in:
parent
82f9098ed5
commit
fb27fcff60
7 changed files with 81 additions and 43 deletions
|
|
@ -4,7 +4,6 @@ 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};
|
||||
|
|
@ -48,15 +47,15 @@ async fn create(conn: Connection<'_, Db>, post_form: Json<candidate::Model>) ->
|
|||
Ok(plain_text_password)
|
||||
}
|
||||
|
||||
#[get("/refresh")]
|
||||
/* #[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;
|
||||
let refresh_token = SessionService::login_user(db, jwt.application_id).await;
|
||||
|
||||
Ok(refresh_token.ok().unwrap())
|
||||
}
|
||||
} */
|
||||
|
||||
#[get("/validate_refresh")]
|
||||
async fn validate(conn: Connection<'_, Db>, uuid_cookie: Result<UUIDCookie, Status>) -> Result<String, Custom<String>> {
|
||||
|
|
@ -75,17 +74,18 @@ async fn login(conn: Connection<'_, Db>, login_form: Json<LoginRequest>) -> Resu
|
|||
let db = conn.into_inner();
|
||||
println!("{} {}", login_form.application_id, login_form.password);
|
||||
|
||||
let jwt = CandidateService::login(db,
|
||||
login_form.application_id,
|
||||
login_form.password.to_owned()).await;
|
||||
let session_token = CandidateService::get_session(db,
|
||||
login_form.application_id,
|
||||
login_form.password.to_string()
|
||||
).await;
|
||||
|
||||
if jwt.is_ok() {
|
||||
if session_token.is_ok() {
|
||||
return Ok(
|
||||
jwt.ok().unwrap()
|
||||
session_token.ok().unwrap()
|
||||
);
|
||||
} else {
|
||||
return Err(
|
||||
custom_err_from_service_err(jwt.err().unwrap())
|
||||
custom_err_from_service_err(session_token.err().unwrap())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +125,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, refresh_token, validate])
|
||||
.mount("/", routes![create, login, hello, whoami, validate])
|
||||
.register("/", catchers![])
|
||||
.launch()
|
||||
.await
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ pub struct Status {
|
|||
|
||||
pub const INVALID_CREDENTIALS_ERROR: ServiceError = ServiceError(Status { code: 401 },
|
||||
"Invalid credentials");
|
||||
pub const EXPIRED_SESSION_ERROR: ServiceError = ServiceError(Status { code: 401 },
|
||||
"Session expired, please login again");
|
||||
|
||||
pub const JWT_ERROR: ServiceError = ServiceError(Status { code: 500 },
|
||||
"Error while encoding JWT");
|
||||
|
||||
|
|
|
|||
|
|
@ -43,4 +43,16 @@ impl Mutation {
|
|||
.insert(db)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn delete_session(
|
||||
db: &DbConn,
|
||||
session_id: Uuid
|
||||
) -> Result<DeleteResult, DbErr> {
|
||||
session::ActiveModel {
|
||||
id: Set(session_id),
|
||||
..Default::default()
|
||||
}
|
||||
.delete(db)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,4 +13,12 @@ impl Query {
|
|||
pub async fn find_session_by_uuid(db: &DbConn, uuid: Uuid) -> Result<Option<session::Model>, DbErr> {
|
||||
Session::find_by_id(uuid).one(db).await
|
||||
}
|
||||
|
||||
// find session by user id
|
||||
pub async fn find_session_by_user_id(db: &DbConn, user_id: i32) -> Result<Option<session::Model>, DbErr> {
|
||||
Session::find()
|
||||
.filter(session::Column::UserId.eq(user_id))
|
||||
.one(db)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use chrono::Duration;
|
||||
use entity::candidate;
|
||||
use sea_orm::{DatabaseConnection, prelude::Uuid, ModelTrait};
|
||||
|
||||
use crate::{crypto, Query, token::{generate_candidate_token, candidate_token::CandidateToken}, error::{ServiceError, USER_NOT_FOUND_ERROR, INVALID_CREDENTIALS_ERROR, DB_ERROR, USER_NOT_FOUND_BY_JWT_ID, USER_NOT_FOUND_BY_SESSION_ID}};
|
||||
use crate::{crypto::{self, hash_sha256}, Query, token::{generate_candidate_token, candidate_token::CandidateToken}, error::{ServiceError, USER_NOT_FOUND_ERROR, INVALID_CREDENTIALS_ERROR, DB_ERROR, USER_NOT_FOUND_BY_JWT_ID, USER_NOT_FOUND_BY_SESSION_ID}, Mutation};
|
||||
|
||||
pub struct CandidateService;
|
||||
|
||||
impl CandidateService {
|
||||
|
||||
#[deprecated(note = "Use login instead")]
|
||||
pub async fn login(db: &DatabaseConnection, id: i32, password: String) -> Result<String, ServiceError> {
|
||||
let candidate = match Query::find_candidate_by_id(db, id).await {
|
||||
Ok(candidate) => match candidate {
|
||||
|
|
@ -26,7 +27,40 @@ impl CandidateService {
|
|||
|
||||
let jwt = generate_candidate_token(candidate); // TODO better error handling
|
||||
Ok(jwt)
|
||||
|
||||
}
|
||||
|
||||
pub async fn get_session(db: &DatabaseConnection, user_id: i32, password: String) -> Result<String, ServiceError> {
|
||||
let candidate = match Query::find_candidate_by_id(db, user_id).await {
|
||||
Ok(candidate) => match candidate {
|
||||
Some(candidate) => candidate,
|
||||
None => return Err(USER_NOT_FOUND_ERROR)
|
||||
},
|
||||
Err(_) => {return Err(DB_ERROR)}
|
||||
};
|
||||
|
||||
// compare passwords
|
||||
match crypto::verify_password(&password, &candidate.code) {
|
||||
Ok(valid) => {
|
||||
if !valid {
|
||||
return Err(INVALID_CREDENTIALS_ERROR)
|
||||
}
|
||||
},
|
||||
Err(_) => {return Err(INVALID_CREDENTIALS_ERROR)}
|
||||
}
|
||||
|
||||
// TODO delete old sessions?
|
||||
|
||||
// user is authenticated, generate a session
|
||||
let random_uuid: Uuid = Uuid::new_v4();
|
||||
|
||||
let jwt = generate_candidate_token(candidate);
|
||||
|
||||
let session = match Mutation::insert_session(db, user_id, random_uuid, hash_sha256(jwt)).await {
|
||||
Ok(session) => session,
|
||||
Err(_) => return Err(DB_ERROR)
|
||||
};
|
||||
|
||||
Ok(session.id.to_string())
|
||||
}
|
||||
|
||||
pub async fn authenticate_candidate(db: &DatabaseConnection, token: CandidateToken) -> Result<candidate::Model, ServiceError> {
|
||||
|
|
@ -50,6 +84,15 @@ impl CandidateService {
|
|||
Err(_) => {return Err(DB_ERROR)}
|
||||
};
|
||||
|
||||
let limit = session.created_at.checked_add_signed(Duration::days(1)).unwrap();
|
||||
let now = chrono::Utc::now().naive_utc();
|
||||
// check if session is expired
|
||||
if now > limit {
|
||||
// delete session
|
||||
Mutation::delete_session(db, session.id).await.unwrap();
|
||||
return Err(USER_NOT_FOUND_BY_SESSION_ID)
|
||||
}
|
||||
|
||||
let candidate = match session.find_related(candidate::Entity).one(db).await {
|
||||
Ok(candidate) => match candidate {
|
||||
Some(candidate) => candidate,
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
pub mod candidate_service;
|
||||
pub mod session_service;
|
||||
pub mod candidate_service;
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
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