Autenticazione Base

Un middleware che fornisce supporto per l'autenticazione Base.

Introduzione all'Autenticazione Base

L'autenticazione Base è un semplice meccanismo di autenticazione HTTP che trasmette nome utente e password tramite l'intestazione Authorization nelle richieste HTTP. Il formato è Authorization: Basic <nomeutente:password in base64>. Sebbene semplice, poiché le credenziali sono solo codificate in Base64 anziché crittografate, viene tipicamente utilizzata con HTTPS per garantire la sicurezza.

Confronto delle Implementazioni di Autenticazione Base nei Framework Comuni

FrameworkLinguaggioImplementazione Autenticazione Base
SalvoRustImplementata tramite il middleware BasicAuth e il BasicAuthValidator personalizzato
ExpressJavaScriptUtilizza il pacchetto middleware express-basic-auth
Spring SecurityJavaConfigurata tramite httpBasic() e implementata con UserDetailsService
ASP.NET CoreC#Utilizza .UseAuthentication() e AddAuthentication(AuthenticationSchemes.Basic)
GinGoImplementata tramite middleware personalizzato o utilizzando il pacchetto gin-contrib/auth

Casi d'Uso

L'autenticazione Base è adatta per i seguenti scenari:

  1. API e Strumenti Interni: Strumenti di gestione e API utilizzati all'interno di un'azienda
  2. Ambienti di Sviluppo e Test: Implementare rapidamente l'autenticazione senza un sistema di login complesso
  3. Protezione Semplice di API: Quando non è richiesto un complesso sistema di gestione utenti
  4. Combinata con Altre Misure di Sicurezza: Come parte di un'architettura di sicurezza multilivello

In Salvo, il middleware di autenticazione Base può essere facilmente integrato nelle rotte. Implementando il tratto BasicAuthValidator, è possibile definire una logica di validazione personalizzata, offrendo grande flessibilità.

Considerazioni

  • Utilizzare sempre con HTTPS per proteggere la trasmissione delle credenziali
  • Non adatto per ambienti di produzione che memorizzano informazioni sensibili
  • Considerare l'uso di metodi di autenticazione più sicuri come JWT o OAuth per ambienti di produzione
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"));
    }
}