Grundlegende Authentifizierung

Eine Middleware, die Unterstützung für Basic Auth bietet.

Einführung in Basic Auth

Basic Auth ist ein einfacher HTTP-Authentifizierungsmechanismus, der Benutzername und Passwort über den Authorization-Header in HTTP-Anfragen überträgt. Das Format lautet Authorization: Basic <base64-Benutzername:Passwort>. Obwohl einfach, da die Anmeldedaten nur Base64-kodiert und nicht verschlüsselt sind, wird es typischerweise mit HTTPS verwendet, um die Sicherheit zu gewährleisten.

Vergleich von Basic Auth-Implementierungen in gängigen Frameworks

FrameworkSpracheBasic Auth-Implementierung
SalvoRustImplementiert über die BasicAuth-Middleware und benutzerdefinierten BasicAuthValidator
ExpressJavaScriptVerwendet das express-basic-auth-Middleware-Paket
Spring SecurityJavaKonfiguriert über httpBasic() und implementiert mit UserDetailsService
ASP.NET CoreC#Verwendet .UseAuthentication() und AddAuthentication(AuthenticationSchemes.Basic)
GinGoImplementiert über benutzerdefinierte Middleware oder das gin-contrib/auth-Paket

Anwendungsfälle

Basic Auth eignet sich für folgende Szenarien:

  1. Interne APIs und Tools: Verwaltungstools und APIs, die innerhalb eines Unternehmens verwendet werden
  2. Entwicklungs- und Testumgebungen: Schnelle Implementierung von Authentifizierung ohne komplexes Login-System
  3. Einfacher API-Schutz: Wenn kein komplexes Benutzerverwaltungssystem erforderlich ist
  4. Kombiniert mit anderen Sicherheitsmaßnahmen: Als Teil einer mehrschichtigen Sicherheitsarchitektur

In Salvo kann die Basic Auth-Middleware einfach in Routen integriert werden. Durch Implementierung des BasicAuthValidator-Traits kann benutzerdefinierte Validierungslogik definiert werden, was große Flexibilität bietet.

Hinweise

  • Immer mit HTTPS verwenden, um die Übertragung der Anmeldedaten zu schützen
  • Nicht geeignet für Produktionsumgebungen, die sensible Informationen speichern
  • Für Produktionsumgebungen sollten sicherere Authentifizierungsmethoden wie JWT oder OAuth in Betracht gezogen werden
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"));
    }
}