#permissions #axum #attributes #uri #resources #macro #access

axum_guard

一套用于保护 Axum URI 资源的属性宏

1 个不稳定版本

0.1.0 2024 年 4 月 1 日

#642 in 过程宏

MIT 许可协议

12KB
163

Axum Grants

Axum Grants 提供了基于权限保护资源的两个 Rust 属性宏。资源权限作为参数传递给属性宏,当前用户的权限包含在一个 Extension 中。可以通过比较当前用户的权限是否包含资源权限来确定对资源的访问。Axum Grants 的基本原理是使用宏将逻辑代码插入到处理函数中,从而通过这段逻辑代码来保护资源。
具体用法请参考 axum_example crate。

准备工作

您需要定义一个结构体,它必须有一个 perms 字段;类型可以是 Vec 或 HashSet。
当有多个权限项时,请使用 HashSet,因为它的 contains 函数的时间复杂度为 O(1)。
例如

#[derive(Debug, Clone, Default)]
pub struct Claims {
    pub user_id: u64, 
    pub user_name: String,
    ...
    pub perms: HashSet<String>, // must have this field
}

在您的 token 中间件中,将 Claims 插入到 Axum Extension 中;这里的 Claims 可以来自数据库、Redis 或 JWT

async fn auth_middle_war(mut req: Request<Body>, next: Next) -> Response<Body> {
    // parse the claims from the token string
    let claims = verify_token(&APP_CFG.app.jwt_secret, token.as_str());
    
    // insert claims into extensions
    req.extensions_mut().insert(claims);
    next.run(req).await
}

保护属性宏的使用说明

当在您的 Axum Handler 上使用保护属性宏时
如果受保护的资源只需要单个权限来访问,您可以设置权限如下

#[protect("opt_qry")]

如果受保护的资源需要多个权限之一来访问,您可以设置权限如下

#[protect(any("opt_crt", "opt_upt", "opt_del"))]

如果受保护的资源需要所有多个权限来访问,您可以设置权限如下

#[protect(all("opt_upt", "opt_del"))]

以下是一个通用示例

#[protect("opt_crt")]
async fn crt_handler(Extension(claims): Extension<Claims>) -> impl IntoResponse {
    // your business code
    ...
}

在上面的示例中,在保护属性宏展开后,最终代码将如下所示

async fn crt_handler(Extension(claims): Extension<Claims>) -> impl IntoResponse {
    if !claims.perms.contains("opt_crt".to_string()) {
        return axum::http::Response::builder()
            .status(axum::http::StatusCode::FORBIDDEN)
            .body(Body::from("Insufficient permissions, need the permission: opt_crt "))
            .unwrap()
    }
    // your business code
    ...
}

保护_diy 属性宏的使用说明

保护_diy 宏设置权限的方法与保护宏的使用方法一致,但保护_diy 宏允许您定义自己的 Axum IntoResponse。
您需要提供一个名为 AxumGrantsResponse 的结构体,它没有字段。这个结构体必须有一个函数,其签名为 fn get_into_response(msg: &str) -> impl IntoResponse。
以下是一个通用示例

pub struct AxumGrantsResponse;
impl AxumGrantsResponse {
    pub fn get_into_response(msg: &str) -> impl IntoResponse {
        // axum::http::Response::builder()
        //     .status(axum::http::StatusCode::FORBIDDEN)
        //     .body(Body::from(msg.to_string())).unwrap()
        axum::Json(json!(
        {
            "cd": "403",
            "msg": msg,
        }))
    }
}

然后您可以使用它如下

#[protect_diy("opt_crt")]
async fn crt_handler(Extension(claims): Extension<Claims>) -> impl IntoResponse {
  // your business code
  ...
}

在上面的示例中,在保护自定义属性宏展开后,最终代码将如下所示

async fn crt_handler(Extension(claims): Extension<Claims>) -> impl IntoResponse {
    if !claims.perms.contains("opt_crt".to_string()) {
        return return AxumGrantsResponse::get_into_response("Insufficient permissions, need the permission: opt_crt ").into_response();
    }
    // your business code
    ...
}

依赖项

~255-700KB
~17K SLoC