有没有办法在 Warp 中作为过滤器的一部分进行验证? [英] Is there a way to do validation as part of a filter in Warp?

查看:50
本文介绍了有没有办法在 Warp 中作为过滤器的一部分进行验证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我定义了一个路由和一个端点函数.我还注入了一些依赖项.

pub fn route1() ->BoxedFilter<(String, ParamType)>{扭曲::获取().and(warp::path::param()).and(warp::filters::query::query()).and(warp::path::end()).装箱()}pub async fn handler1(请求参数,参数:参数类型,依赖:依赖类型,) ->结果<impl warp::Reply, warp::Rejection>{}

let api = api::routes::route1().and(warp::any().map(move || 依赖)).and_then(api::hanlders::hander1);

这似乎一切正常.

但是,我希望能够在多个端点前放置一些东西,以检查查询参数中的有效键.在 handler1 里面我可以添加:

if !param.key_valid {返回 Ok(warp::reply::with_status(warp::reply::json(&""),状态代码::BAD_REQUEST,));}

我不想将它单独添加到每个处理程序中.

看起来我应该可以通过 filter 做到这一点,但我无法弄清楚.我试过使用 .map() 但随后返回多个项目将其转换为一个元组,我必须更改我的下游函数签名.理想情况下,我想找到一种方法来添加验证或其他过滤器,以便在没有任何下游值了解它们的情况下拒绝请求.

解决方案

warp 的 拒绝示例:

<块引用>

拒绝表示过滤器不应继续处理请求,但不同的过滤器可以处理它的情况.

<块引用>

从div-by"标题中提取分母,或使用 DivideByZero 拒绝.

你需要

  1. 使用Filter::and_then 采用现有过滤器(在本例中为 query())并执行验证.如果验证失败,返回自定义拒绝.
  2. 使用Filter::recover 以适当处理自定义拒绝和任何其他可能的错误.

适用于您的情况:

使用 serde::Deserialize;使用 std::{convert::Infallible, net::IpAddr};使用 warp::{filters::BoxedFilter, http::StatusCode, reject::Reject, Filter, Rejection, Reply};fn route1() ->BoxedFilter<(String, ParamType)>{扭曲::获取().and(warp::path::param()).and(validated_query()).and(warp::path::end()).装箱()}#[派生(调试)]结构无效;impl Reject for Invalid {}fnvalidated_query() ->impl Filter+ 复制 {warp::filters::query::query().and_then(|param: ParamType| async move {如果 param.valid {好的(参数)} 别的 {错误(扭曲::拒绝::自定义(无效))}})}async fn report_invalid(r: Rejection) ->结果<impl Reply, Infallible>{让回复 = warp::reply::reply();如果让 Some(Invalid) = r.find() {好的(warp::reply::with_status(reply, StatusCode::BAD_REQUEST))} 别的 {//在这里做更好的错误处理好的(扭曲::回复::with_status(回复,StatusCode::INTERNAL_SERVER_ERROR,))}}异步 fn 处理程序 1(_请求参数,_param: 参数类型,_dependency:依赖类型,) ->结果<impl warp::Reply, warp::Rejection>{好的(扭曲::回复::回复())}结构依赖类型;#[派生(反序列化)]结构参数类型{有效:布尔,}#[东京::主要]异步 fn main() {让 api = route1().and(warp::any().map(move || DependencyType)).and_then(handler1).recover(report_invalid);让 ip: IpAddr = "127.0.0.1".parse().unwrap();让端口 = 8888;warp::serve(api).run((ip, port)).await;}

去掉无关行的 curl 输出:

% curl -v '127.0.0.1:8888/dummy/?valid=false'<HTTP/1.1 400 错误请求% curl -v '127.0.0.1:8888/dummy/?valid=true'<HTTP/1.1 200 正常

Cargo.toml

[依赖项]翘曲 = "0.2.2"serde = { version = "1.0.104", features = ["derive"] }tokio = { version = "0.2.13", features = ["full"] }

I have a route and an endpoint function defined. I've also injected some dependencies.

pub fn route1() -> BoxedFilter<(String, ParamType)> {
    warp::get()
        .and(warp::path::param())
        .and(warp::filters::query::query())
        .and(warp::path::end())
        .boxed()
}

pub async fn handler1(
    query: String,
    param: ParamType,
    dependency: DependencyType,
) -> Result<impl warp::Reply, warp::Rejection> {
}

let api = api::routes::route1()
    .and(warp::any().map(move || dependency))
    .and_then(api::hanlders::hander1);

This all seems to work fine.

However, I want to be able to have something that sits in front of several endpoints that checks for a valid key in the query parameter. Inside handler1 I can add:

if !param.key_valid {
    return Ok(warp::reply::with_status(
        warp::reply::json(&""),
        StatusCode::BAD_REQUEST,
    ));
}

I do not want to add this to every handler individually.

It seems like I should be able to do it via filter, but I can't figure it out. I've tried using .map() but then returning multiple items shifts it to a tuple and I have to change my downstream function signature. Ideally I want to find a way to add verification or other filters that can reject the request without any downstream values knowing about them.

解决方案

This is effectively demonstrated by warp's rejection example:

Rejections represent cases where a filter should not continue processing the request, but a different filter could process it.

Extract a denominator from a "div-by" header, or reject with DivideByZero.

You need to

  1. Use Filter::and_then to take the existing filter (in this case query()) and perform the validation. If the validation fails, return a custom rejection.
  2. Use Filter::recover to appropriately handle the custom rejection and any other possible errors.

Applied to your situation:

use serde::Deserialize;
use std::{convert::Infallible, net::IpAddr};
use warp::{filters::BoxedFilter, http::StatusCode, reject::Reject, Filter, Rejection, Reply};

fn route1() -> BoxedFilter<(String, ParamType)> {
    warp::get()
        .and(warp::path::param())
        .and(validated_query())
        .and(warp::path::end())
        .boxed()
}

#[derive(Debug)]
struct Invalid;
impl Reject for Invalid {}

fn validated_query() -> impl Filter<Extract = (ParamType,), Error = Rejection> + Copy {
    warp::filters::query::query().and_then(|param: ParamType| async move {
        if param.valid {
            Ok(param)
        } else {
            Err(warp::reject::custom(Invalid))
        }
    })
}

async fn report_invalid(r: Rejection) -> Result<impl Reply, Infallible> {
    let reply = warp::reply::reply();

    if let Some(Invalid) = r.find() {
        Ok(warp::reply::with_status(reply, StatusCode::BAD_REQUEST))
    } else {
        // Do better error handling here
        Ok(warp::reply::with_status(
            reply,
            StatusCode::INTERNAL_SERVER_ERROR,
        ))
    }
}

async fn handler1(
    _query: String,
    _param: ParamType,
    _dependency: DependencyType,
) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(warp::reply::reply())
}

struct DependencyType;

#[derive(Deserialize)]
struct ParamType {
    valid: bool,
}

#[tokio::main]
async fn main() {
    let api = route1()
        .and(warp::any().map(move || DependencyType))
        .and_then(handler1)
        .recover(report_invalid);

    let ip: IpAddr = "127.0.0.1".parse().unwrap();
    let port = 8888;
    warp::serve(api).run((ip, port)).await;
}

And the output of curl with irrelevant lines removed:

% curl -v '127.0.0.1:8888/dummy/?valid=false'
< HTTP/1.1 400 Bad Request

% curl -v '127.0.0.1:8888/dummy/?valid=true'
< HTTP/1.1 200 OK

Cargo.toml

[dependencies]
warp = "0.2.2"
serde = { version = "1.0.104", features = ["derive"] }
tokio = { version = "0.2.13", features = ["full"] }

这篇关于有没有办法在 Warp 中作为过滤器的一部分进行验证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆