ntex-basicauth 0.2.0

A Basic Authentication middleware for ntex web framework.
Documentation

ntex-basicauth

A Basic Authentication middleware designed for the ntex web framework.

Crates.io Documentation License: MIT

Features

  • Cache - Built-in authentication result cache to reduce validation overhead
  • Flexible Configuration - Supports multiple user validation methods
  • Path Filtering - Supports skipping authentication for specific paths
  • BCrypt Support - Optional BCrypt password hashing (requires bcrypt feature)
  • JSON Response - Optional JSON error response (requires json feature)
  • Custom Validator - Support for custom user validation logic
  • Regex Paths - Regular expression path matching (requires regex feature)

Installation

Add the dependency in your Cargo.toml:

[dependencies]
ntex-basicauth = "^0"
[dependencies]
ntex-basicauth = { version = "^0", features = ["bcrypt"] }

Quick Start

Basic Usage

use ntex::web;
use ntex_basicauth::BasicAuth;
use std::collections::HashMap;

#[ntex::main]
async fn main() -> std::io::Result<()> {
    // Create user list
    let mut users = HashMap::new();
    users.insert("admin".to_string(), "secret".to_string());
    users.insert("user".to_string(), "password".to_string());

    web::HttpServer::new(move || {
        web::App::new()
            .wrap(BasicAuth::with_users(users.clone()))
            .route("/protected", web::get().to(protected_handler))
            .route("/public", web::get().to(public_handler))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

async fn protected_handler() -> &'static str {
    "This is protected content!"
}

async fn public_handler() -> &'static str {
    "This is public content"
}

Using the Builder Pattern

use ntex_basicauth::{BasicAuthBuilder, PathFilter};
use std::time::Duration;

let auth = BasicAuthBuilder::new()
    .user("admin", "secret")
    .user("user", "password")
    .realm("My Application")
    .cache_ttl(Duration::from_secs(300)) // 5 minutes cache
    .cache_size_limit(500)
    .path_filter(
        PathFilter::new()
            .skip_prefix("/public/")
            .skip_exact("/health")
            .skip_suffix(".css")
            .skip_regex(r"^/assets/.*\.(js|css|png|jpg)$") // requires regex feature
    )
    .build()
    .unwrap();

web::App::new()
    .wrap(auth)
    .service(web::resource("/api/data").to(handler))

BCrypt Password Support

After enabling the bcrypt feature:

use ntex_basicauth::{BasicAuthBuilder, BcryptUserValidator};

let auth = BasicAuthBuilder::new()
    .bcrypt_user("admin", "$2b$12$...") // BCrypt hash
    .bcrypt_user_with_password("user", "password") // Will hash automatically
    .build()
    .unwrap();

Custom Validator

use ntex_basicauth::{UserValidator, Credentials, AuthResult, BasicAuthBuilder};
use std::sync::Arc;

struct DatabaseValidator {
    // Database connection pool, etc.
}

impl UserValidator for DatabaseValidator {
    async fn validate(&self, credentials: &Credentials) -> AuthResult<bool> {
        // Query database
        let user_exists = check_user_in_database(
            &credentials.username, 
            &credentials.password
        ).await;
        Ok(user_exists)
    }
}

// Using custom validator
let auth = BasicAuthBuilder::new()
    .validator(Arc::new(DatabaseValidator {}))
    .build()
    .unwrap();

Getting User Information

Get authenticated user information in the request handler:

use ntex::web;
use ntex_basicauth::{extract_credentials, get_username, is_user};

async fn handler(req: web::HttpRequest) -> web::Result<String> {
    // Get full authentication info
    if let Some(credentials) = extract_credentials(&req) {
        return Ok(format!("User: {}", credentials.username));
    }

    // Get only the username
    if let Some(username) = get_username(&req) {
        return Ok(format!("Welcome, {}!", username));
    }

    // Check if specific user
    if is_user(&req, "admin") {
        return Ok("Admin access granted".to_string());
    }

    Ok("Unknown user".to_string())
}

Configuration Options

BasicAuthConfig

let config = BasicAuthConfig::new(validator)
    .realm("My Application".to_string())           // Set authentication realm
    .disable_cache()                               // Disable cache
    .cache_size_limit(1000)                        // Set cache size limit
    .path_filter(filter);                          // Set path filter

PathFilter

let filter = PathFilter::new()
    .skip_exact("/health")          // Skip exact path
    .skip_prefix("/public/")        // Skip prefix match
    .skip_suffix(".css");           // Skip suffix match

Error Handling

When authentication fails, the middleware returns HTTP 401 status code and corresponding error information:

{
    "code": 401,
    "message": "Authentication required",
    "error": "Invalid credentials"
}

Error types:

  • MissingHeader - Missing Authorization header
  • InvalidFormat - Invalid Authorization header format
  • InvalidBase64 - Invalid Base64 encoding
  • InvalidCredentials - Invalid user credentials
  • ValidationFailed - User validation failed

Performance Optimization

Cache

Authentication cache is enabled by default, which can significantly reduce repeated validation overhead:

use std::time::Duration;

let auth = BasicAuthBuilder::new()
    .users(users)
    .cache_ttl(Duration::from_secs(600))    // 10 minutes
    .cache_size_limit(1000)                 // Max 1000 entries
    .cache_cleanup_interval(Duration::from_secs(300)) // Cleanup every 5 min
    .build()
    .unwrap();

License

This project is licensed under the MIT License.