#axum #guard #middleware #router #role #action #routing

axum-guard-router

an axum middleware to create a guard router

2 unstable releases

0.2.1 Jul 17, 2024
0.1.3 Jul 16, 2024

#1260 in HTTP server

Apache-2.0

32KB
607 lines

axum-guard-router

An axum middleware to create a guard router.

Build Test

More information about this crate can be found in the crate documentation.

High level features

  • Custom router resoure and action name.
  • Custom router roles.
  • Creatge guard to check the routing marked with roles, resource or action.

Usage example

use axum::{
    extract::Path,
    http::StatusCode,
    response::{IntoResponse, Response},
    routing::{get, post, put},
    Json, Router,
};
use axum_guard_router::{action, GuardRouter, OnGuard};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

#[derive(Clone)]
struct MyGuard;

impl OnGuard for MyGuard {
    async fn on_guard(&self, resource: &str, action: &str) -> Result<(), Response> {
        println!("on_guard: resource={resource} action={action}");
        // check permission by resource and action
        if action == "my:update" {
            return Err((
                StatusCode::FORBIDDEN,
                format!("resource={resource} action={action}"),
            )
                .into_response());
        }

        Ok(())
    }
}

#[tokio::main]
async fn main() {
    let guid = Arc::new(MyGuard);
    let app = Router::new().nest(
        "/user",
        GuardRouter::new("admin:user", guid.clone())
            // one path for multipe actions
            .route(
                "/admin/:id",
                action::get("my:get", get_user).put("my:update", update_user),
            )
            // one path for only one action with multipe axum::routing
            .action("my:write", "/", get(get_user).post(create_user))
            .build()
            // nest router
            .nest(
                "/nest",
                GuardRouter::new("admin:user", guid.clone())
                    .action("my:get", "/:id", get(get_user))
                    .action("my:update", "/:id", put(update_user))
                    .build(),
            ),
    );

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3100").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

#[derive(Serialize, Deserialize)]
struct CreateUser {
    username: String,
}

#[derive(Serialize, Deserialize)]
struct User {
    id: u64,
    username: String,
}

async fn get_user(Path(id): Path<u64>) -> impl IntoResponse {
    let user = User {
        id,
        username: "test".to_string(),
    };
    (StatusCode::OK, Json(user))
}

async fn create_user(Json(payload): Json<CreateUser>) -> impl IntoResponse {
    let user = User {
        id: 1337,
        username: payload.username,
    };
    (StatusCode::CREATED, Json(user))
}

async fn update_user(Path(id): Path<u64>, Json(mut user): Json<User>) -> impl IntoResponse {
    user.id = id;
    (StatusCode::OK, Json(user))
}

License

This project is licensed under the Apache License 2.0.

Dependencies

~5–12MB
~127K SLoC