From 778e90e8e3e4239bc5d00f2202e75127ef5d1691 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sun, 21 May 2023 00:55:29 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20A=C3=B1ade=20gesti=C3=B3n=20de=20se?= =?UTF-8?q?siones=20v=C3=ADa=20cookie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pagetop/Cargo.toml | 2 + pagetop/config/settings.predefined.toml | 6 +- pagetop/src/app.rs | 21 ++++ pagetop/src/config.rs | 137 +++++++++++++++--------- pagetop/src/server.rs | 4 +- 5 files changed, 116 insertions(+), 54 deletions(-) diff --git a/pagetop/Cargo.toml b/pagetop/Cargo.toml index e1c53ecc..9c1cdde5 100644 --- a/pagetop/Cargo.toml +++ b/pagetop/Cargo.toml @@ -57,6 +57,8 @@ fluent-templates = "0.8.0" unic-langid = "0.9.1" actix-web = "4" +actix-session = { version = "0.7.2", features = ["cookie-session"] } + actix-web-files = { package = "actix-files", version = "0.6.2" } actix-web-static-files = "4.0.1" static-files = "0.2.3" diff --git a/pagetop/config/settings.predefined.toml b/pagetop/config/settings.predefined.toml index f275018f..1372ad98 100644 --- a/pagetop/config/settings.predefined.toml +++ b/pagetop/config/settings.predefined.toml @@ -36,7 +36,7 @@ static_files = "" [log] # 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" # En terminal ("Stdout") o archivos "Daily", "Hourly", "Minutely" o "Endless". rolling = "Stdout" @@ -51,3 +51,7 @@ format = "Full" # Configuración del servidor web. bind_address = "localhost" 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 diff --git a/pagetop/src/app.rs b/pagetop/src/app.rs index b1971350..d69f5b8e 100644 --- a/pagetop/src/app.rs +++ b/pagetop/src/app.rs @@ -11,6 +11,10 @@ use crate::{config, locale, server, trace, LazyStatic}; #[cfg(feature = "database")] 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 std::io::Error; @@ -50,9 +54,22 @@ impl Application { module::all::run_migrations(); // Prepara el servidor web. + let secret_key = get_secret_key(); let server = server::HttpServer::new(move || { server::App::new() .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) .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 { Err(FatalError::NotFound(request)) } diff --git a/pagetop/src/config.rs b/pagetop/src/config.rs index f3f525bc..9f692f7b 100644 --- a/pagetop/src/config.rs +++ b/pagetop/src/config.rs @@ -23,7 +23,8 @@ //! 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. //! -//! 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 //! *config/default.toml* si existe. @@ -130,8 +131,8 @@ use std::env; /// Directorio donde se encuentran los archivos de configuración. const CONFIG_DIR: &str = "config"; -/// Todos los valores originales de la configuración en forma de pares `clave = valor` recogidos de -/// los archivos de configuración. +/// Valores originales de la configuración en forma de pares `clave = valor` recogidos de los +/// archivos de configuración. pub static CONFIG: LazyStatic = LazyStatic::new(|| { // 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()); @@ -167,7 +168,7 @@ macro_rules! define_config { ( $SETTINGS:ident as $Settings:ty $(, $key:literal => $value:literal)*$(,)* ) => { $crate::doc_comment! { 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), "`]." ), pub static $SETTINGS: $crate::LazyStatic<$Settings> = $crate::LazyStatic::new(|| { @@ -196,113 +197,145 @@ pub struct Settings { } #[derive(Debug, Deserialize)] -/// Sección `[app]` de los ajustes globales. +/// Sección `[app]` de los ajustes de configuración globales. /// /// Ver [`Settings`]. pub struct App { - /// Valor predefinido: *"PageTop Application"* + /// El nombre de la aplicación. + /// Por defecto: *"PageTop Application"*. 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, - /// Valor predefinido: *"Basic"* + /// Tema predeterminado. + /// Por defecto: *"Basic"*. pub theme: String, - /// Valor predefinido: *"en-US"* + /// Idioma (localización) predeterminado. + /// Por defecto: *"en-US"*. 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, - /// Valor predefinido: *"Slant"* + /// Rótulo de texto ASCII al arrancar: *"Off"*, *"Slant"*, *"Small"*, *"Speed"* o *"Starwars"*. + /// Por defecto: *"Slant"*. 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, } #[derive(Debug, Deserialize)] -/// Sección `[database]` de los ajustes globales. +/// Sección `[database]` de los ajustes de configuración globales. /// /// Ver [`Settings`]. pub struct Database { - /// Valor predefinido: *""* + /// Tipo de base de datos: *"mysql"*, *"postgres"* ó *"sqlite"*. + /// Por defecto: *""*. 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, - /// Valor predefinido: *""* + /// Usuario de conexión a la base de datos (para mysql/postgres). + /// Por defecto: *""*. 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, - /// Valor predefinido: *"localhost"* + /// Servidor de conexión a la base de datos (para mysql/postgres). + /// Por defecto: *"localhost"*. 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, - /// Valor predefinido: *5* + /// Número máximo de conexiones habilitadas. + /// Por defecto: *5*. pub max_pool_size: u32, } #[derive(Debug, Deserialize)] -/// Sección `[dev]` de los ajustes globales. +/// Sección `[dev]` de los ajustes de configuración globales. /// /// Ver [`Settings`]. 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, } #[derive(Debug, Deserialize)] -/// Sección `[log]` de los ajustes globales. +/// Sección `[log]` de los ajustes de configuración globales. /// /// Ver [`Settings`]. 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, - /// 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, - /// Valor predefinido: *"log"* + /// Directorio para los archivos de traza (si `rolling` != *"Stdout"*). + /// Por defecto: *"log"*. pub path: String, - /// Valor predefinido: *"tracing.log"* + /// Prefijo para los archivos de traza (si `rolling` != *"Stdout"*). + /// Por defecto: *"tracing.log"*. pub prefix: String, - /// Valor predefinido: *"Full"* + /// Presentación de las trazas. Puede ser *"Full"*, *"Compact"*, *"Pretty"* o *"Json"*. + /// Por defecto: *"Full"*. pub format: String, } #[derive(Debug, Deserialize)] -/// Sección `[server]` de los ajustes globales. +/// Sección `[server]` de los ajustes de configuración globales. /// /// Ver [`Settings`]. pub struct Server { - /// Valor predefinido: *"localhost"* + /// Dirección del servidor web. + /// Por defecto: *"localhost"*. pub bind_address: String, - /// Valor predefinido: *8088* + /// Puerto del servidor web. + /// Por defecto: *8088*. 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, // [app] - "app.name" => "PageTop Application", - "app.description" => "Developed with the amazing PageTop framework.", - "app.theme" => "Basic", - "app.language" => "en-US", - "app.direction" => "ltr", - "app.startup_banner" => "Slant", + "app.name" => "PageTop Application", + "app.description" => "Developed with the amazing PageTop framework.", + "app.theme" => "Basic", + "app.language" => "en-US", + "app.direction" => "ltr", + "app.startup_banner" => "Slant", // [database] - "database.db_type" => "", - "database.db_name" => "", - "database.db_user" => "", - "database.db_pass" => "", - "database.db_host" => "localhost", - "database.db_port" => 0, - "database.max_pool_size" => 5, + "database.db_type" => "", + "database.db_name" => "", + "database.db_user" => "", + "database.db_pass" => "", + "database.db_host" => "localhost", + "database.db_port" => 0, + "database.max_pool_size" => 5, // [dev] - "dev.static_files" => "", + "dev.static_files" => "", // [log] - "log.tracing" => "Info", - "log.rolling" => "Stdout", - "log.path" => "log", - "log.prefix" => "tracing.log", - "log.format" => "Full", + "log.tracing" => "Info", + "log.rolling" => "Stdout", + "log.path" => "log", + "log.prefix" => "tracing.log", + "log.format" => "Full", // [server] - "server.bind_address" => "localhost", - "server.bind_port" => 8088, + "server.bind_address" => "localhost", + "server.bind_port" => 8088, + "server.session_lifetime" => 604800, ); diff --git a/pagetop/src/server.rs b/pagetop/src/server.rs index 17f145a5..6ceae9e4 100644 --- a/pagetop/src/server.rs +++ b/pagetop/src/server.rs @@ -1,7 +1,9 @@ //! 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::{ - 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_static_files::ResourceFiles;