Autenticação Básica

Um middleware que fornece suporte para Autenticação Básica.

Introdução à Autenticação Básica

A Autenticação Básica é um mecanismo simples de autenticação HTTP que transmite um nome de usuário e senha através do cabeçalho Authorization em requisições HTTP. O formato é Authorization: Basic <base64 nome de usuário:senha>. Embora simples, como as credenciais são apenas codificadas em Base64 em vez de criptografadas, normalmente é usada com HTTPS para garantir segurança.

Comparação das Implementações de Autenticação Básica em Frameworks Comuns

FrameworkLinguagemImplementação de Autenticação Básica
SalvoRustImplementado via middleware BasicAuth e BasicAuthValidator personalizado
ExpressJavaScriptUsa o pacote de middleware express-basic-auth
Spring SecurityJavaConfigurado via httpBasic() e implementado com UserDetailsService
ASP.NET CoreC#Usa .UseAuthentication() e AddAuthentication(AuthenticationSchemes.Basic)
GinGoImplementado via middleware personalizado ou usando o pacote gin-contrib/auth

Casos de Uso

A Autenticação Básica é adequada para os seguintes cenários:

  1. APIs e Ferramentas Internas: Ferramentas de gerenciamento e APIs usadas dentro de uma empresa
  2. Ambientes de Desenvolvimento e Teste: Implementar autenticação rapidamente sem um sistema de login complexo
  3. Proteção Simples de API: Quando um sistema complexo de gerenciamento de usuários não é necessário
  4. Combinado com Outras Medidas de Segurança: Como parte de uma arquitetura de segurança em várias camadas

No Salvo, o middleware de Autenticação Básica pode ser facilmente integrado em rotas. Ao implementar a trait BasicAuthValidator, é possível definir lógica de validação personalizada, oferecendo grande flexibilidade.

Considerações

  • Sempre use com HTTPS para proteger a transmissão de credenciais
  • Não é adequado para ambientes de produção que armazenam informações sensíveis
  • Considere usar métodos de autenticação mais seguros, como JWT ou OAuth, para ambientes de produção
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"));
    }
}