Autenticación Básica

Un middleware que proporciona soporte para Autenticación Básica.

Introducción a la Autenticación Básica

La Autenticación Básica es un mecanismo simple de autenticación HTTP que transmite un nombre de usuario y contraseña a través del encabezado Authorization en las solicitudes HTTP. El formato es Authorization: Basic <base64 usuario:contraseña>. Aunque es simple, dado que las credenciales solo están codificadas en Base64 en lugar de estar encriptadas, normalmente se utiliza con HTTPS para garantizar la seguridad.

Comparación de Implementaciones de Autenticación Básica en Frameworks Comunes

FrameworkLenguajeImplementación de Autenticación Básica
SalvoRustImplementado a través del middleware BasicAuth y BasicAuthValidator personalizado
ExpressJavaScriptUtiliza el paquete de middleware express-basic-auth
Spring SecurityJavaConfigurado mediante httpBasic() e implementado con UserDetailsService
ASP.NET CoreC#Usa .UseAuthentication() y AddAuthentication(AuthenticationSchemes.Basic)
GinGoImplementado mediante middleware personalizado o usando el paquete gin-contrib/auth

Casos de Uso

La Autenticación Básica es adecuada para los siguientes escenarios:

  1. APIs y Herramientas Internas: Herramientas de gestión y APIs utilizadas dentro de una empresa
  2. Entornos de Desarrollo y Pruebas: Implementar autenticación rápidamente sin un sistema de inicio de sesión complejo
  3. Protección Simple de APIs: Cuando no se requiere un sistema complejo de gestión de usuarios
  4. Combinado con Otras Medidas de Seguridad: Como parte de una arquitectura de seguridad multicapa

En Salvo, el middleware de Autenticación Básica puede integrarse fácilmente en las rutas. Al implementar el trait BasicAuthValidator, se puede definir lógica de validación personalizada, ofreciendo gran flexibilidad.

Consideraciones

  • Utilizar siempre con HTTPS para proteger la transmisión de credenciales
  • No es adecuado para entornos de producción que almacenan información sensible
  • Considerar el uso de métodos de autenticación más seguros como JWT u OAuth para entornos de producción
main.rs
Cargo.toml
use salvo::basic_auth::{BasicAuth, BasicAuthValidator};
use salvo::prelude::*;

// Custom validator implementing BasicAuthValidator trait
struct Validator;
impl BasicAuthValidator for Validator {
    // Validate username and password combination
    async fn validate(&self, username: &str, password: &str, _depot: &mut Depot) -> bool {
        username == "root" && password == "pwd"
    }
}

// Simple handler that returns "Hello" for authenticated requests
#[handler]
async fn hello() -> &'static str {
    "Hello"
}

// Create router with basic authentication middleware
fn route() -> Router {
    // Initialize basic authentication handler with our validator
    let auth_handler = BasicAuth::new(Validator);
    // Apply authentication middleware to the router
    Router::with_hoop(auth_handler).goal(hello)
}

#[tokio::main]
async fn main() {
    // Initialize logging
    tracing_subscriber::fmt().init();

    // Bind server to port 8698 and start serving
    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    Server::new(acceptor).serve(route()).await;
}

#[cfg(test)]
mod tests {
    use salvo::prelude::*;
    use salvo::test::{ResponseExt, TestClient};

    #[tokio::test]
    async fn test_basic_auth() {
        // Create a service instance from our router for testing purposes
        let service = Service::new(super::route());

        // Test case 1: Verify successful authentication with valid credentials
        let content = TestClient::get("http://0.0.0.0:8698/")
            .basic_auth("root", Some("pwd")) // Use correct username/password
            .send(&service) // Send the request to the service
            .await
            .take_string() // Extract response body as string
            .await
            .unwrap();
        // Verify response contains expected "Hello" message
        assert!(content.contains("Hello"));

        // Test case 2: Verify authentication failure with invalid password
        let content = TestClient::get("http://0.0.0.0:8698/")
            .basic_auth("root", Some("pwd2")) // Use incorrect password
            .send(&service) // Send the request to the service
            .await
            .take_string() // Extract response body as string
            .await
            .unwrap();
        // Verify response contains "Unauthorized" error
        assert!(content.contains("Unauthorized"));
    }
}