#rate-limiting #web-framework #thruster #middleware #super #request #store

thruster-rate-limit

为thruster Web框架提供的超简单速率限制中间件

4个版本 (2个稳定版)

1.0.1 2023年5月30日
0.1.1 2023年5月29日
0.1.0 2023年5月29日

#2044Web编程

每月 37次下载

GPL-3.0-or-later

18KB
232

thruster-rate-limit

为thruster Web框架提供的超简单速率限制中间件。

目前仅支持thruster的hyper后端,基本上必须启用hyper_server功能!

目录

简单示例

struct ServerState {
    rate_limiter: RateLimiter<MapStore>,
}

#[context_state]
struct RequestState(RateLimiter<MapStore>, Box<RateLimiterConf>);
type Ctx = TypedHyperContext<RequestState>;

struct RateLimiterConf;
impl Configuration<RequestState> for RateLimiterConf {}

#[middleware_fn]
async fn root(mut context: Ctx, _next: MiddlewareNext<Ctx>) -> MiddlewareResult<Ctx> {
    context.body(BODY_STR);
    return Ok(context);
}

fn generate_context(request: HyperRequest, state: &ServerState, _path: &str) -> Ctx {
    return Ctx::new(
        request,
        RequestState(state.rate_limiter.clone(), Box::new(RateLimiterConf)),
    );
}

#[tokio::test]
async fn hello_world() {
    let rate_limiter = RateLimiter::default();

    let app = App::<HyperRequest, Ctx, ServerState>::create(
        generate_context,
        ServerState { rate_limiter },
    )
    .middleware("/", m![rate_limit_middleware])
    .get(ROUTE, m![root])
    .commit();

    let response = Testable::get(&app, ROUTE, vec![])
        .await
        .unwrap()
        .expect_status(200, "OK");

    assert_eq!(response.body_string(), BODY_STR);
}

选项

#[derive(Clone)]
pub struct Options {
    pub max: usize,
    pub per_s: usize,
}

#[derive(Clone)]
pub struct RateLimiter<S: Store + Clone> {
    pub options: Options,
    pub routes: Vec<(String, Options)>,
    pub store: S,
}
  • routes:将不同选项应用于不同路由 更多信息
  • max:允许的最大请求数量 per_s
  • per_s:何时重置max
  • store:任何实现Store特质的对象,库提供了2个存储

配置

目前功能相对基础,但您可以通过实现Configuration特质来根据需求扩展速率限制器的功能

pub trait Configuration<S: Send> {
    fn should_limit(&self, _context: &TypedHyperContext<S>) -> bool {
        return true;
    }
    fn get_key(&self, context: &TypedHyperContext<S>) -> String {
        if let Some(request) = context.hyper_request.as_ref() {
            if let Some(ip) = request.ip {
                return ip.to_string();
            }
        }

        return "".to_string();
    }
}

存储

简单的内存存储

#[derive(Clone)]
pub struct MapStore {
    hash_map: Arc<Mutex<HashMap<String, MapValue>>>,
}

[需要redis_store功能] Redis存储

#[derive(Clone)]
pub struct RedisStore {
    connection_manager: ConnectionManager,
}

不同路由,不同设置

简单来说,这在例如,对于登录路由只想每分钟有5个请求时很有用。

let rate_limiter = RateLimiter::new(Options::new(1, 100), MapStore::new())
    .override_routes(vec![
        // Options::new(max, per_s)
        ("/user/login".to_string(), Options::new(5, 60)),
        // limit some expensive route for example, reset every 2 minutes
        ("/user/:id/calculate".to_string(), Options::new(20, 60 * 2)),
    ]);

依赖

~10–20MB
~282K SLoC