Añade gestión de sesiones vía cookie

This commit is contained in:
Manuel Cillero 2023-05-21 00:55:29 +02:00
parent 058f43bf95
commit 778e90e8e3
5 changed files with 116 additions and 54 deletions

View file

@ -57,6 +57,8 @@ fluent-templates = "0.8.0"
unic-langid = "0.9.1" unic-langid = "0.9.1"
actix-web = "4" actix-web = "4"
actix-session = { version = "0.7.2", features = ["cookie-session"] }
actix-web-files = { package = "actix-files", version = "0.6.2" } actix-web-files = { package = "actix-files", version = "0.6.2" }
actix-web-static-files = "4.0.1" actix-web-static-files = "4.0.1"
static-files = "0.2.3" static-files = "0.2.3"

View file

@ -36,7 +36,7 @@ static_files = ""
[log] [log]
# Traza de ejecución: "Error", "Warn", "Info", "Debug" o "Trace". # Traza de ejecución: "Error", "Warn", "Info", "Debug" o "Trace".
# Ejemplos: "Error,actix_server::builder=Info,tracing_actix_web=Debug". # Por ejemplo: "Error,actix_server::builder=Info,tracing_actix_web=Debug".
tracing = "Info" tracing = "Info"
# En terminal ("Stdout") o archivos "Daily", "Hourly", "Minutely" o "Endless". # En terminal ("Stdout") o archivos "Daily", "Hourly", "Minutely" o "Endless".
rolling = "Stdout" rolling = "Stdout"
@ -51,3 +51,7 @@ format = "Full"
# Configuración del servidor web. # Configuración del servidor web.
bind_address = "localhost" bind_address = "localhost"
bind_port = 8088 bind_port = 8088
# Duración de la cookie de sesión (en segundos), es decir, el tiempo desde que
# se crea la sesión hasta que caduca la cookie. El valor 0 indica "hasta que se
# cierre el navegador". Por defecto es una semana.
session_lifetime = 604800

View file

@ -11,6 +11,10 @@ use crate::{config, locale, server, trace, LazyStatic};
#[cfg(feature = "database")] #[cfg(feature = "database")]
use crate::db; use crate::db;
use actix_session::config::{BrowserSession, PersistentSession, SessionLifecycle};
use actix_session::storage::CookieSessionStore;
use actix_session::SessionMiddleware;
use actix_web::cookie::{time::Duration, Key};
use actix_web::dev::Server; use actix_web::dev::Server;
use std::io::Error; use std::io::Error;
@ -50,9 +54,22 @@ impl Application {
module::all::run_migrations(); module::all::run_migrations();
// Prepara el servidor web. // Prepara el servidor web.
let secret_key = get_secret_key();
let server = server::HttpServer::new(move || { let server = server::HttpServer::new(move || {
server::App::new() server::App::new()
.wrap(tracing_actix_web::TracingLogger::default()) .wrap(tracing_actix_web::TracingLogger::default())
.wrap(
SessionMiddleware::builder(CookieSessionStore::default(), secret_key.clone())
.session_lifecycle(match config::SETTINGS.server.session_lifetime {
0 => SessionLifecycle::BrowserSession(BrowserSession::default()),
_ => SessionLifecycle::PersistentSession(
PersistentSession::default().session_ttl(Duration::seconds(
config::SETTINGS.server.session_lifetime,
)),
),
})
.build(),
)
.configure(module::all::configure_services) .configure(module::all::configure_services)
.default_service(server::web::route().to(service_not_found)) .default_service(server::web::route().to(service_not_found))
}) })
@ -98,6 +115,10 @@ fn print_on_startup() {
} }
} }
fn get_secret_key() -> Key {
Key::generate()
}
async fn service_not_found(request: server::HttpRequest) -> ResultPage<Markup, FatalError> { async fn service_not_found(request: server::HttpRequest) -> ResultPage<Markup, FatalError> {
Err(FatalError::NotFound(request)) Err(FatalError::NotFound(request))
} }

View file

@ -23,7 +23,8 @@
//! 1. **config/common.toml**, útil para los ajustes comunes a cualquier entorno. Estos valores //! 1. **config/common.toml**, útil para los ajustes comunes a cualquier entorno. Estos valores
//! podrán ser sobrescritos al fusionar los archivos de configuración restantes. //! podrán ser sobrescritos al fusionar los archivos de configuración restantes.
//! //!
//! 2. **config/{file}.toml**, donde *{file}* se define con la variable de entorno PAGETOP_RUN_MODE: //! 2. **config/{file}.toml**, donde *{file}* se define con la variable de entorno
//! `PAGETOP_RUN_MODE`:
//! //!
//! * Si no está definida se asumirá *default* por defecto y PageTop intentará cargar el archivo //! * Si no está definida se asumirá *default* por defecto y PageTop intentará cargar el archivo
//! *config/default.toml* si existe. //! *config/default.toml* si existe.
@ -130,8 +131,8 @@ use std::env;
/// Directorio donde se encuentran los archivos de configuración. /// Directorio donde se encuentran los archivos de configuración.
const CONFIG_DIR: &str = "config"; const CONFIG_DIR: &str = "config";
/// Todos los valores originales de la configuración en forma de pares `clave = valor` recogidos de /// Valores originales de la configuración en forma de pares `clave = valor` recogidos de los
/// los archivos de configuración. /// archivos de configuración.
pub static CONFIG: LazyStatic<ConfigData> = LazyStatic::new(|| { pub static CONFIG: LazyStatic<ConfigData> = LazyStatic::new(|| {
// Modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Por defecto 'default'. // Modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Por defecto 'default'.
let run_mode = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| "default".into()); let run_mode = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| "default".into());
@ -167,7 +168,7 @@ macro_rules! define_config {
( $SETTINGS:ident as $Settings:ty $(, $key:literal => $value:literal)*$(,)* ) => { ( $SETTINGS:ident as $Settings:ty $(, $key:literal => $value:literal)*$(,)* ) => {
$crate::doc_comment! { $crate::doc_comment! {
concat!( concat!(
"Declara y asigna los valores predefinidos para los ajustes de configuración ", "Valores asignados o predefinidos para los ajustes de configuración globales ",
"asociados a la estructura [`", stringify!($Settings), "`]." "asociados a la estructura [`", stringify!($Settings), "`]."
), ),
pub static $SETTINGS: $crate::LazyStatic<$Settings> = $crate::LazyStatic::new(|| { pub static $SETTINGS: $crate::LazyStatic<$Settings> = $crate::LazyStatic::new(|| {
@ -196,113 +197,145 @@ pub struct Settings {
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
/// Sección `[app]` de los ajustes globales. /// Sección `[app]` de los ajustes de configuración globales.
/// ///
/// Ver [`Settings`]. /// Ver [`Settings`].
pub struct App { pub struct App {
/// Valor predefinido: *"PageTop Application"* /// El nombre de la aplicación.
/// Por defecto: *"PageTop Application"*.
pub name: String, pub name: String,
/// Valor predefinido: *"Developed with the amazing PageTop framework."* /// Una descripción breve de la aplicación.
/// Por defecto: *"Developed with the amazing PageTop framework."*.
pub description: String, pub description: String,
/// Valor predefinido: *"Basic"* /// Tema predeterminado.
/// Por defecto: *"Basic"*.
pub theme: String, pub theme: String,
/// Valor predefinido: *"en-US"* /// Idioma (localización) predeterminado.
/// Por defecto: *"en-US"*.
pub language: String, pub language: String,
/// Valor predefinido: *"ltr"* /// Dirección predeterminada para el texto: *"ltr"* (de izquierda a derecha), *"rtl"* (de
/// derecha a izquierda) o *"auto"*.
/// Por defecto: *"ltr"*.
pub direction: String, pub direction: String,
/// Valor predefinido: *"Slant"* /// Rótulo de texto ASCII al arrancar: *"Off"*, *"Slant"*, *"Small"*, *"Speed"* o *"Starwars"*.
/// Por defecto: *"Slant"*.
pub startup_banner: String, pub startup_banner: String,
/// Valor predefinido: según variable de entorno PAGETOP_RUN_MODE, o *"default"* si no lo está /// Por defecto: según variable de entorno `PAGETOP_RUN_MODE`, o *"default"* si no lo está.
pub run_mode: String, pub run_mode: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
/// Sección `[database]` de los ajustes globales. /// Sección `[database]` de los ajustes de configuración globales.
/// ///
/// Ver [`Settings`]. /// Ver [`Settings`].
pub struct Database { pub struct Database {
/// Valor predefinido: *""* /// Tipo de base de datos: *"mysql"*, *"postgres"* ó *"sqlite"*.
/// Por defecto: *""*.
pub db_type: String, pub db_type: String,
/// Valor predefinido: *""* /// Nombre (para mysql/postgres) o referencia (para sqlite) de la base de datos.
/// Por defecto: *""*.
pub db_name: String, pub db_name: String,
/// Valor predefinido: *""* /// Usuario de conexión a la base de datos (para mysql/postgres).
/// Por defecto: *""*.
pub db_user: String, pub db_user: String,
/// Valor predefinido: *""* /// Contraseña para la conexión a la base de datos (para mysql/postgres).
/// Por defecto: *""*.
pub db_pass: String, pub db_pass: String,
/// Valor predefinido: *"localhost"* /// Servidor de conexión a la base de datos (para mysql/postgres).
/// Por defecto: *"localhost"*.
pub db_host: String, pub db_host: String,
/// Valor predefinido: *0* /// Puerto de conexión a la base de datos, normalmente 3306 (para mysql) ó 5432 (para postgres).
/// Por defecto: *0*.
pub db_port: u16, pub db_port: u16,
/// Valor predefinido: *5* /// Número máximo de conexiones habilitadas.
/// Por defecto: *5*.
pub max_pool_size: u32, pub max_pool_size: u32,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
/// Sección `[dev]` de los ajustes globales. /// Sección `[dev]` de los ajustes de configuración globales.
/// ///
/// Ver [`Settings`]. /// Ver [`Settings`].
pub struct Dev { pub struct Dev {
/// Valor predefinido: *""* /// Los archivos estáticos requeridos por la aplicación se integran de manera predeterminada en
/// el binario ejecutable. Sin embargo, durante el desarrollo puede resultar útil servir estos
/// archivos desde su propio directorio para evitar compilar cada vez que se modifican. En este
/// caso, normalmente, basta con indicar la ruta "../ruta/static".
/// Por defecto: *""*.
pub static_files: String, pub static_files: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
/// Sección `[log]` de los ajustes globales. /// Sección `[log]` de los ajustes de configuración globales.
/// ///
/// Ver [`Settings`]. /// Ver [`Settings`].
pub struct Log { pub struct Log {
/// Valor predefinido: *"Info"* /// Filtro, o combinación de filtros separados por coma, para la traza de ejecución: *"Error"*,
/// *"Warn"*, *"Info"*, *"Debug"* o *"Trace"*.
/// Por ejemplo: "Error,actix_server::builder=Info,tracing_actix_web=Debug".
/// Por defecto: *"Info"*.
pub tracing: String, pub tracing: String,
/// Valor predefinido: *"Stdout"* /// Muestra la traza en el terminal (*"Stdout"*) o queda registrada en archivos con rotación
/// *"Daily"*, *"Hourly"*, *"Minutely"* o *"Endless"*.
/// Por defecto: *"Stdout"*.
pub rolling: String, pub rolling: String,
/// Valor predefinido: *"log"* /// Directorio para los archivos de traza (si `rolling` != *"Stdout"*).
/// Por defecto: *"log"*.
pub path: String, pub path: String,
/// Valor predefinido: *"tracing.log"* /// Prefijo para los archivos de traza (si `rolling` != *"Stdout"*).
/// Por defecto: *"tracing.log"*.
pub prefix: String, pub prefix: String,
/// Valor predefinido: *"Full"* /// Presentación de las trazas. Puede ser *"Full"*, *"Compact"*, *"Pretty"* o *"Json"*.
/// Por defecto: *"Full"*.
pub format: String, pub format: String,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
/// Sección `[server]` de los ajustes globales. /// Sección `[server]` de los ajustes de configuración globales.
/// ///
/// Ver [`Settings`]. /// Ver [`Settings`].
pub struct Server { pub struct Server {
/// Valor predefinido: *"localhost"* /// Dirección del servidor web.
/// Por defecto: *"localhost"*.
pub bind_address: String, pub bind_address: String,
/// Valor predefinido: *8088* /// Puerto del servidor web.
/// Por defecto: *8088*.
pub bind_port: u16, pub bind_port: u16,
/// Duración en segundos para la sesión (0 indica "hasta que se cierre el navegador").
/// Por defecto: *604800* (7 días).
pub session_lifetime: i64,
} }
define_config!(SETTINGS as Settings, define_config!(SETTINGS as Settings,
// [app] // [app]
"app.name" => "PageTop Application", "app.name" => "PageTop Application",
"app.description" => "Developed with the amazing PageTop framework.", "app.description" => "Developed with the amazing PageTop framework.",
"app.theme" => "Basic", "app.theme" => "Basic",
"app.language" => "en-US", "app.language" => "en-US",
"app.direction" => "ltr", "app.direction" => "ltr",
"app.startup_banner" => "Slant", "app.startup_banner" => "Slant",
// [database] // [database]
"database.db_type" => "", "database.db_type" => "",
"database.db_name" => "", "database.db_name" => "",
"database.db_user" => "", "database.db_user" => "",
"database.db_pass" => "", "database.db_pass" => "",
"database.db_host" => "localhost", "database.db_host" => "localhost",
"database.db_port" => 0, "database.db_port" => 0,
"database.max_pool_size" => 5, "database.max_pool_size" => 5,
// [dev] // [dev]
"dev.static_files" => "", "dev.static_files" => "",
// [log] // [log]
"log.tracing" => "Info", "log.tracing" => "Info",
"log.rolling" => "Stdout", "log.rolling" => "Stdout",
"log.path" => "log", "log.path" => "log",
"log.prefix" => "tracing.log", "log.prefix" => "tracing.log",
"log.format" => "Full", "log.format" => "Full",
// [server] // [server]
"server.bind_address" => "localhost", "server.bind_address" => "localhost",
"server.bind_port" => 8088, "server.bind_port" => 8088,
"server.session_lifetime" => 604800,
); );

View file

@ -1,7 +1,9 @@
//! Tipos y funciones para operar con el servidor web ([actix-web](https://docs.rs/actix-web)). //! Tipos y funciones para operar con el servidor web ([actix-web](https://docs.rs/actix-web)).
pub use actix_session::Session;
pub use actix_web::{ pub use actix_web::{
http, web, App, HttpMessage, HttpRequest, HttpResponse, HttpServer, Responder, cookie, http, web, App, HttpMessage, HttpRequest, HttpResponse, HttpServer, Responder,
}; };
pub use actix_web_files::Files as ActixFiles; pub use actix_web_files::Files as ActixFiles;
pub use actix_web_static_files::ResourceFiles; pub use actix_web_static_files::ResourceFiles;