当前位置: 首页 > 工具软件 > Actix > 使用案例 >

十一、Actix-web 拦截器中间件

李良策
2023-12-01

十一、Actix-web 拦截器中间件
  
  在编写 web 项目时,对于登录状态,或权限的 “拦截器” 是必不可少的,本节我们来看看 actix-web 中对 http 的请求的策略拦截。
  
  actix-web 中的 “拦截器” 是通过 middleware 来实现的。首先来定义一个中间件,其中大部分为模板代码,从 actix-web 的 middleware 源中都可以找到。最重要的是底部的 fn call(&mut self, req: ServiceRequest) -> Self::Future {} 方法。这里我们实现一个简单的逻辑:header 中有 token 则通过。否则拦截请求,并使用 http 401 的权限不足状态,来返回错误。
  
  boot/middleware/auth.rs

use std::cell::RefCell;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};

use actix_web::{Error, error};
use actix_web::body::MessageBody;
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
use actix_web::http::HeaderValue;
use futures::Future;
use futures::future::{ok, Ready};

// custom request auth middleware
pub struct Auth;

impl<S, B> Transform<S> for Auth
    where
        S: Service<Request=ServiceRequest, Response=ServiceResponse<B>, Error=Error> + 'static,
        S::Future: 'static,
        B: MessageBody + 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Transform = AuthMiddleware<S>;
    type InitError = ();
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(AuthMiddleware {
            service: Rc::new(RefCell::new(service))
        })
    }
}

pub struct AuthMiddleware<S> {
    service: Rc<RefCell<S>>,
}

impl<S, B> Service for AuthMiddleware<S>
    where
        S: Service<Request=ServiceRequest, Response=ServiceResponse<B>, Error=Error> + 'static,
        S::Future: 'static,
        B: MessageBody + 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output=Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        let mut svc = self.service.clone();

        Box::pin(async move {
            let value = HeaderValue::from_str("").unwrap();
            let token = req.headers().get("token").unwrap_or(&value);
            if token.len() > 0 || req.path().to_string() == "/login" {
                Ok(svc.call(req).await?)
            } else {
                Err(error::ErrorUnauthorized("err"))
            }
        })

    }
}

   main.rs 中,我们对中间件进行集成:

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    boot::start();
    HttpServer::new(move || App::new()
        .wrap(boot::middleware::Auth)	// 增加了这里
        .service(module::handler::api_routes())
    ).bind(boot::global().addr())?.run().await
}

 
  现在可以启动服务,尝试访问一下。并通过对 header 中添加 token 或 不带 token 访问来测试一下区别。好了,本节就到这 ~
  
 

 类似资料: