Rust Warp Bett实践:API密钥验证

Rust Warp Bett实践:API密钥验证,rust,api-key,rust-warp,Rust,Api Key,Rust Warp,我正在尝试开始使用warp并测试api密钥验证。下面的代码可以工作,但不太好。 验证函数从标头中提取密钥。成功验证后,密钥不再使用,但“handle_request”函数需要有一个输入参数 您能否建议如何避免不必要的输入参数和更干净的api密钥验证方法 提前谢谢 use std::convert::Infallible; use std::error::Error; use serde::{Deserialize, Serialize}; use warp::http::{Response, S

我正在尝试开始使用warp并测试api密钥验证。下面的代码可以工作,但不太好。 验证函数从标头中提取密钥。成功验证后,密钥不再使用,但“handle_request”函数需要有一个输入参数

您能否建议如何避免不必要的输入参数和更干净的api密钥验证方法

提前谢谢

use std::convert::Infallible;
use std::error::Error;
use serde::{Deserialize, Serialize};
use warp::http::{Response, StatusCode};
use warp::{reject, Filter, Rejection, Reply};
//use futures::future;
// use headers::{Header, HeaderMapExt};
// use http::header::HeaderValue;
// use http::HeaderMap;

extern crate pretty_env_logger;
#[macro_use] extern crate log;

#[derive(Deserialize, Serialize)]
struct Params {
    key1: String,
    key2: u32,
}

#[derive(Debug)]
struct Unauthorized;

impl reject::Reject for Unauthorized {}

#[tokio::main]
async fn main() {
    pretty_env_logger::init();
    // get /exampel?key1=value&key2=42
    let route1 = warp::get().and(key_validation())
        .and(warp::query::<Params>())
        .and_then(handle_request);
       
    let routes = route1.recover(handle_rejection);
    warp::serve(routes)
        .run(([127, 0, 0, 1], 3030))
        .await;
}

async fn handle_request(api_key:String, params: Params) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(Response::builder().body(format!("key1 = {}, key2 = {}", params.key1, params.key2)))
}

fn key_validation() -> impl Filter<Extract = (String,), Error = Rejection> + Copy {
    warp::header::<String>("x-api-key").and_then(|n: String| async move {
        if n == "test" {
            Ok(n)
        } else {
            Err(reject::custom(Unauthorized))
        }
    })
}

// JSON replies

/// An API error serializable to JSON.
#[derive(Serialize)]
struct ErrorMessage {
    code: u16,
    message: String,
}

// This function receives a `Rejection` and tries to return a custom
// value, otherwise simply passes the rejection along.
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
    let code;
    let message;

    if err.is_not_found() {
        code = StatusCode::NOT_FOUND;
        message = "NOT_FOUND";
    } else if let Some(Unauthorized) = err.find() {
        code = StatusCode::UNAUTHORIZED;
        message = "Invalide API key";
    } else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
       // We can handle a specific error, here METHOD_NOT_ALLOWED,
        // and render it however we want
        code = StatusCode::METHOD_NOT_ALLOWED;
        message = "METHOD_NOT_ALLOWED";
    } else {
        // We should have expected this... Just log and say its a 500
        error!("unhandled rejection: {:?}", err);
        code = StatusCode::INTERNAL_SERVER_ERROR;
        message = "UNHANDLED_REJECTION";
    }

    let json = warp::reply::json(&ErrorMessage {
        code: code.as_u16(),
        message: message.into(),
    });

    Ok(warp::reply::with_status(json, code))
}

只需使您的方法不提取任何内容:

async fn handle_请求(params:params)->结果{
Ok(Response::builder().body(格式!(“key1={},key2={}”,params.key1,params.key2)))
}
fn key_validation()->impl Filter+Copy{
warp::header::(“x-api-key”)。然后(| n:String |异步移动{
如果n==“测试”{
好(())
}否则{
错误(拒绝::自定义(未经授权))
}
})
}
您可能需要放弃密钥验证结果值,请使用:

let route1=warp::get()
.和(密钥验证()
.untuple_one()
和(warp::query::())
。然后(处理请求);

Hi@Netwave,感谢您的快速回答。我尝试了你的解决方案,并将结果添加到我的问题中。如果您能再次查看并告诉我您是否有其他解决此问题的方法,那将是非常棒的。@JimmyFoobar,您可能需要在密钥验证后使用
解偶联来丢弃空值。
error[E0271]: type mismatch resolving `<warp::filter::and_then::AndThen<impl warp::Filter+Copy, [closure@src/main.rs:44:50: 50:6]> as warp::filter::FilterBase>::Extract == ()`
  --> src/main.rs:43:24
   |
43 | fn key_validation() -> impl Filter<Extract = (), Error = Rejection> + Copy {
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found `()`
   |
   = note:  expected tuple `(_,)`
           found unit type `()`
async fn handle_request(params: Params) -> Result<impl warp::Reply, warp::Rejection> {
    Ok(Response::builder().body(format!("key1 = {}, key2 = {}", params.key1, params.key2)))
}

fn key_validation() -> impl Filter<Extract = ((),), Error = Rejection> + Copy {
    warp::header::<String>("x-api-key").and_then(|n: String| async move {
        if n == "test" {
            Ok(())
        } else {
            Err(reject::custom(Unauthorized))
        }
    })
}
error[E0593]: function is expected to take 2 arguments, but it takes 1 argument
  --> src/main.rs:31:19
   |
31 |         .and_then(handle_request);
   |                   ^^^^^^^^^^^^^^ expected function that takes 2 arguments
...
39 | async fn handle_request(params: Params) -> Result<impl warp::Reply, warp::Rejection> {
   | ------------------------------------------------------------------------------------ takes 1 argument
   |
   = note: required because of the requirements on the impl of `warp::generic::Func<((), Params)>` for `fn(Params) -> impl Future {handle_request}`

[dependencies]
log = "0.4"
pretty_env_logger = "0.4"
tokio = { version = "1", features = ["full"] }
warp = "0.3"
serde = { version = "1.0", features = ["derive"] }
futures = { version = "0.3", default-features = false, features = ["alloc"] }