You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

是否可将Rocket的request guard应用到所有路由实现全局Basic HTTP认证

Rocket v0.5-rc 全局Basic HTTP Auth实现方案

你需要的核心逻辑是绕开Fairing不能直接返回响应的限制,同时实现无遗漏的全局认证,不需要修改任何现有路由代码,推荐以下方案:

实现原理

利用Fairing的on_request钩子完成全局认证校验,通过请求本地缓存标记认证结果,要么直接转发到专用的未授权路由,要么配合全局自定义错误捕获器(Catcher)统一返回未授权响应,完全避免路由漏配问题,也不需要在on_response阶段擦除原有响应内容。

完整代码示例

1. 定义基础结构和认证守卫

use rocket::{Request, Data, fairing::{Fairing, Info, Kind}, http::Status, request::{FromRequest, Outcome}};
use rocket::serde::json::json;

// 你可以直接替换为自己已经实现的BasicAuthentication结构
struct BasicAuthentication {
    username: String,
}

#[rocket::async_trait]
impl<'r> FromRequest<'r> for BasicAuthentication {
    type Error = ();

    async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
        // 这里写入你的Basic Auth校验逻辑:解析Authorization头、解码、对比账号密码
        let auth_header = request.headers().get_one("Authorization");
        match auth_header {
            Some(header) if header.starts_with("Basic ") => {
                // 校验通过返回成功
                Outcome::Success(BasicAuthentication { username: "valid_user".to_string() })
            }
            _ => Outcome::Failure((Status::Unauthorized, ()))
        }
    }
}

// 定义未授权标记,用于请求本地缓存
struct Unauthorized;

2. 实现认证Fairing

struct GlobalAuthFairing;

#[rocket::async_trait]
impl Fairing for GlobalAuthFairing {
    fn info(&self) -> Info {
        Info {
            name: "Global Basic Auth",
            kind: Kind::Request,
        }
    }

    async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
        // 可配置白名单路径,比如健康检查、公开静态资源不需要校验
        if request.uri().path() == "/health" {
            return;
        }
        // 执行认证校验
        let auth_outcome = request.guard::<BasicAuthentication>().await;
        if auth_outcome.is_failure() {
            // 认证失败后给请求打上未授权标记
            request.local_cache(|| Unauthorized);
            // 直接修改请求URI指向未授权专用路由,不会执行原有路由逻辑
            request.set_method(rocket::http::Method::Get);
            request.set_uri(rocket::uri!("/__unauthorized")).unwrap();
        }
    }
}

3. 注册未授权路由启动服务

// 未授权请求专用返回路由
#[get("/__unauthorized")]
async fn unauthorized_resp() -> (Status, rocket::serde::json::Value) {
    (
        Status::Unauthorized,
        json!({"error": "Unauthorized", "message": "Please provide valid Basic Auth credentials"})
    )
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .attach(GlobalAuthFairing)
        .mount("/", routes![unauthorized_resp /* 其余业务路由都可以放在这里 */])
}

可选替代方案:用全局Catcher处理

如果你不想新增专用路由,也可以把认证失败的逻辑放到全局错误捕获器里处理,Fairing只负责打标记:

// 全局404捕获器
#[catch(404)]
async fn global_catcher(req: &Request<'_>) -> (Status, rocket::serde::json::Value) {
    // 检查请求是否有未授权标记
    if req.local_cache(|| Option::<Unauthorized>::None).is_some() {
        return (
            Status::Unauthorized,
            json!({"error": "Unauthorized"})
        );
    }
    // 正常404返回
    (Status::NotFound, json!({"error": "Not Found"}))
}

// 启动时注册捕获器即可
#[launch]
fn rocket() -> _ {
    rocket::build()
        .attach(GlobalAuthFairing)
        .mount("/", routes![/* 所有业务路由 */])
        .register("/", catchers![global_catcher])
}

方案优势

  • 完全全局拦截,不需要给每个路由单独加认证参数,不会出现漏配
  • 认证失败后不会执行原有路由的业务逻辑,完全避免了on_response阶段需要擦除响应内容的问题
  • 可灵活配置白名单路径,适配公开接口场景

内容的提问来源于stack exchange,提问作者TimY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 22:36:10