From e07dee7fde46f300201d9465fbaf4e3bc8c3e6f9 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Fri, 1 Apr 2022 18:59:17 +0200 Subject: [PATCH] Redirect user after successful login --- src/controllers/base_controller.rs | 8 ++++++ src/controllers/login_controller.rs | 24 +++++++++++++++-- src/controllers/mod.rs | 3 ++- src/data/mod.rs | 3 ++- src/data/session_identity.rs | 40 +++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 src/controllers/base_controller.rs create mode 100644 src/data/session_identity.rs diff --git a/src/controllers/base_controller.rs b/src/controllers/base_controller.rs new file mode 100644 index 0000000..5a0b87a --- /dev/null +++ b/src/controllers/base_controller.rs @@ -0,0 +1,8 @@ +use actix_web::HttpResponse; + +/// Create a redirect user response +pub fn redirect_user(uri: &str) -> HttpResponse { + HttpResponse::Found() + .append_header(("Location", uri)) + .finish() +} \ No newline at end of file diff --git a/src/controllers/login_controller.rs b/src/controllers/login_controller.rs index c9c5d19..3f7b4da 100644 --- a/src/controllers/login_controller.rs +++ b/src/controllers/login_controller.rs @@ -6,6 +6,8 @@ use askama::Template; use crate::actors::users_actor::{LoginResult, UsersActor}; use crate::actors::users_actor; use crate::constants::APP_NAME; +use crate::controllers::base_controller::redirect_user; +use crate::data::session_identity::SessionIdentity; #[derive(Template)] #[template(path = "base_login_page.html")] @@ -36,16 +38,34 @@ pub async fn login_route(users: web::Data>, let mut danger = String::new(); let mut login = String::new(); + // Check if user is already authenticated + if SessionIdentity::is_authenticated(&id) { + return redirect_user("/"); + } + // Try to authenticate user if let Some(req) = &req { + // TODO : check request origin + login = req.login.clone(); let response: LoginResult = users.send(users_actor::LoginRequest { login: login.clone(), password: req.password.clone(), }).await.unwrap(); - // TODO : save auth in case of successful authentication - danger = format!("{:?}", response) + match response { + LoginResult::Success(user) => { + id.remember(SessionIdentity::from_user(&user).serialize()); + + return redirect_user("/"); + } + + c => { + // TODO : add bruteforce detection + log::warn!("Failed login for username {} : {:?}", login, c); + danger = "Login failed.".to_string(); + } + } } diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs index dcc2c8a..dd17ed2 100644 --- a/src/controllers/mod.rs +++ b/src/controllers/mod.rs @@ -1,2 +1,3 @@ pub mod assets_controller; -pub mod login_controller; \ No newline at end of file +pub mod login_controller; +pub mod base_controller; \ No newline at end of file diff --git a/src/data/mod.rs b/src/data/mod.rs index d3866f6..91797cb 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,4 +1,5 @@ pub mod app_config; pub mod user; pub mod service; -pub mod entity_manager; \ No newline at end of file +pub mod entity_manager; +pub mod session_identity; \ No newline at end of file diff --git a/src/data/session_identity.rs b/src/data/session_identity.rs new file mode 100644 index 0000000..0cf6165 --- /dev/null +++ b/src/data/session_identity.rs @@ -0,0 +1,40 @@ +use std::fmt::Display; + +use actix_identity::Identity; + +use crate::data::user::User; + +pub struct SessionIdentity { + pub id: String, + pub is_admin: bool, +} + +impl SessionIdentity { + pub fn from_user(user: &User) -> Self { + Self { + id: user.uid.clone(), + is_admin: user.admin, + } + } + + pub fn deserialize(input: D) -> Self { + let input = input.to_string(); + let mut iter = input.split('-'); + Self { + id: iter.next().unwrap_or_default().to_string(), + is_admin: iter.next().unwrap_or_default() == "true", + } + } + + pub fn serialize(&self) -> String { + format!("{}-{}", self.id, self.is_admin) + } + + pub fn is_authenticated(i: &Identity) -> bool { + i.identity() + .as_ref() + .map(Self::deserialize) + .map(|s| !s.id.is_empty()) + .unwrap_or(false) + } +} \ No newline at end of file