基本認証

Basic Authをサポートするミドルウェアを提供します。

Basic Auth 概要

Basic Authは、HTTPリクエストヘッダーにAuthorizationフィールドを含めてユーザー名とパスワードを送信する、シンプルなHTTP認証メカニズムです。形式はAuthorization: Basic <base64 username:password>となります。簡易的ですが、認証情報がBase64エンコードされるだけで暗号化されないため、通常はHTTPSと併用してセキュリティを確保する必要があります。

主要フレームワークにおけるBasic Auth実装の比較

フレームワーク言語Basic Auth 実装方法
SalvoRustBasicAuthミドルウェアとカスタムBasicAuthValidatorによる実装
ExpressJavaScriptexpress-basic-authミドルウェアパッケージの使用
Spring SecurityJavahttpBasic()設定とUserDetailsServiceによる実装
ASP.NET CoreC#.UseAuthentication()AddAuthentication(AuthenticationSchemes.Basic)の使用
GinGoカスタムミドルウェアまたはgin-contrib/authパッケージの使用

適用シナリオ

Basic Authは以下のような場面に適しています:

  1. 内部APIおよびツール:社内で使用する管理ツールやAPI
  2. 開発・テスト環境:複雑なログインシステムを必要とせず迅速に認証を実装する場合
  3. 簡易的なAPI保護:複雑なユーザー管理システムが必要ない場合
  4. 他のセキュリティ対策との併用:多層セキュリティアーキテクチャの一部として

Salvoでは、Basic Authミドルウェアをルーティングに簡単に統合でき、BasicAuthValidatorトレイトを実装することで認証ロジックをカスタマイズできるため、非常に柔軟性があります。

注意事項

  • 認証情報の送信を保護するため、常にHTTPSと併用してください
  • 機密情報を扱う本番環境には適していません
  • 本番環境ではJWTやOAuthなど、より安全な認証方式の使用を検討してください
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"));
    }
}