Can redirect user on successful login

This commit is contained in:
Pierre HUBERT 2022-04-02 19:44:13 +02:00
parent da74acaed8
commit f08fddc79c
7 changed files with 46 additions and 10 deletions

7
Cargo.lock generated
View File

@ -395,6 +395,7 @@ dependencies = [
"mime_guess", "mime_guess",
"serde", "serde",
"serde_json", "serde_json",
"urlencoding",
"uuid", "uuid",
] ]
@ -1625,6 +1626,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "urlencoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.8.2" version = "0.8.2"

View File

@ -20,3 +20,4 @@ uuid = { version = "0.8.2", features = ["v4"] }
mime_guess = "2.0.4" mime_guess = "2.0.4"
askama = "0.11.1" askama = "0.11.1"
futures-util = "0.3.21" futures-util = "0.3.21"
urlencoding = "2.1.0"

View File

@ -1,8 +1,22 @@
use std::fmt::Display;
use actix_web::HttpResponse; use actix_web::HttpResponse;
use crate::constants::LOGIN_ROUTE;
/// Create a redirect user response /// Create a redirect user response
pub fn redirect_user(uri: &str) -> HttpResponse { pub fn redirect_user(uri: &str) -> HttpResponse {
HttpResponse::Found() HttpResponse::Found()
.append_header(("Location", uri)) .append_header(("Location", uri))
.finish() .finish()
} }
/// Redirect user to authenticate him
pub fn redirect_user_for_login<P: Display>(redirect_uri: P) -> HttpResponse {
HttpResponse::Found()
.append_header((
"Location",
format!("{}?redirect={}", LOGIN_ROUTE, urlencoding::encode(&redirect_uri.to_string()))
))
.finish()
}

View File

@ -16,6 +16,7 @@ struct BaseLoginPage {
success: String, success: String,
page_title: &'static str, page_title: &'static str,
app_name: &'static str, app_name: &'static str,
redirect_uri: String,
} }
#[derive(Template)] #[derive(Template)]
@ -41,6 +42,7 @@ pub struct LoginRequestBody {
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct LoginRequestQuery { pub struct LoginRequestQuery {
logout: Option<bool>, logout: Option<bool>,
redirect: Option<String>,
} }
/// Authenticate user /// Authenticate user
@ -52,6 +54,14 @@ pub async fn login_route(users: web::Data<Addr<UsersActor>>,
let mut success = String::new(); let mut success = String::new();
let mut login = String::new(); let mut login = String::new();
let redirect_uri = match query.redirect.as_deref() {
None => "/",
Some(s) => match s.starts_with('/') && !s.starts_with("//") {
true => s,
false => "/",
}
};
// Check if user session must be closed // Check if user session must be closed
if let Some(true) = query.logout { if let Some(true) = query.logout {
id.forget(); id.forget();
@ -60,7 +70,7 @@ pub async fn login_route(users: web::Data<Addr<UsersActor>>,
// Check if user is already authenticated // Check if user is already authenticated
if SessionIdentity(&id).is_authenticated() { if SessionIdentity(&id).is_authenticated() {
return redirect_user("/"); return redirect_user(redirect_uri);
} }
// Check if user is setting a new password // Check if user is setting a new password
@ -78,7 +88,7 @@ pub async fn login_route(users: web::Data<Addr<UsersActor>>,
danger = "Failed to change password!".to_string(); danger = "Failed to change password!".to_string();
} else { } else {
SessionIdentity(&id).set_status(SessionStatus::SignedIn); SessionIdentity(&id).set_status(SessionStatus::SignedIn);
return redirect_user("/"); return redirect_user(redirect_uri);
} }
} }
} }
@ -100,7 +110,7 @@ pub async fn login_route(users: web::Data<Addr<UsersActor>>,
if user.need_reset_password { if user.need_reset_password {
SessionIdentity(&id).set_status(SessionStatus::NeedNewPassword); SessionIdentity(&id).set_status(SessionStatus::NeedNewPassword);
} else { } else {
return redirect_user("/"); return redirect_user(redirect_uri);
} }
} }
@ -122,6 +132,7 @@ pub async fn login_route(users: web::Data<Addr<UsersActor>>,
danger, danger,
success, success,
app_name: APP_NAME, app_name: APP_NAME,
redirect_uri: urlencoding::encode(redirect_uri).to_string(),
}, },
min_pass_len: MIN_PASS_LEN, min_pass_len: MIN_PASS_LEN,
}.render().unwrap()); }.render().unwrap());
@ -136,6 +147,7 @@ pub async fn login_route(users: web::Data<Addr<UsersActor>>,
danger, danger,
success, success,
app_name: APP_NAME, app_name: APP_NAME,
redirect_uri: urlencoding::encode(redirect_uri).to_string(),
}, },
login, login,
}.render().unwrap()) }.render().unwrap())

View File

@ -9,8 +9,8 @@ use actix_web::{dev::{forward_ready, Service, ServiceRequest, ServiceResponse, T
use actix_web::body::EitherBody; use actix_web::body::EitherBody;
use askama::Template; use askama::Template;
use crate::constants::{ADMIN_ROUTES, AUTHENTICATED_ROUTES, LOGIN_ROUTE}; use crate::constants::{ADMIN_ROUTES, AUTHENTICATED_ROUTES};
use crate::controllers::base_controller::redirect_user; use crate::controllers::base_controller::redirect_user_for_login;
use crate::data::session_identity::{SessionIdentity, SessionIdentityData}; use crate::data::session_identity::{SessionIdentity, SessionIdentityData};
// There are two steps in middleware processing. // There are two steps in middleware processing.
@ -100,7 +100,8 @@ impl<S, B> Service<ServiceRequest> for AuthInnerMiddleware<S>
// Redirect user to login page // Redirect user to login page
if !identity.is_auth() && (req.path().starts_with(ADMIN_ROUTES) || if !identity.is_auth() && (req.path().starts_with(ADMIN_ROUTES) ||
req.path().starts_with(AUTHENTICATED_ROUTES)) { req.path().starts_with(AUTHENTICATED_ROUTES)) {
return Ok(req.into_response(redirect_user(LOGIN_ROUTE)) let path = req.path().to_string();
return Ok(req.into_response(redirect_user_for_login(path))
.map_into_right_body()); .map_into_right_body());
} }

View File

@ -1,6 +1,6 @@
{% extends "base_login_page.html" %} {% extends "base_login_page.html" %}
{% block content %} {% block content %}
<form action="/login" method="post"> <form action="/login?redirect={{ redirect_uri }}" method="post">
<div> <div>
<div class="form-floating"> <div class="form-floating">
<input name="login" type="text" required class="form-control" id="floatingName" placeholder="unsername" <input name="login" type="text" required class="form-control" id="floatingName" placeholder="unsername"

View File

@ -1,6 +1,6 @@
{% extends "base_login_page.html" %} {% extends "base_login_page.html" %}
{% block content %} {% block content %}
<form action="/login" method="post" id="reset_password_form"> <form action="/login?redirect={{ redirect_uri }}" method="post" id="reset_password_form">
<div> <div>
<p>You need to configure a new password:</p> <p>You need to configure a new password:</p>
@ -47,6 +47,7 @@
form.submit(); form.submit();
}) })
</script> </script>