十一、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 AuthwhereS: 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>whereS: 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 访问来测试一下区别。好了,本节就到这 ~