How to return an early response from an actix-web middleware?

I'm kind of late to the party but the best way to do this from within Actix middleware is using futures::future::Either. You can see how it's used here: https://github.com/actix/examples/blob/master/middleware/middleware/src/redirect.rs.

The left hand side of Either will be a Future which passes the response to the next stage in the chain. The right hand side will be a response (usually HttpResponse) if you wish to return the response early.


You can create your own type, Authorized, implement FromRequest for it and define Authorized as an argument in the handlers that should be checked for authorization.

Simplified example:

use actix_web::dev::Payload;
use actix_web::error::ErrorUnauthorized;
use actix_web::{web, App, Error, FromRequest, HttpRequest, HttpResponse, HttpServer};

fn main() {
    HttpServer::new(move || App::new().route("/", web::to(index)))
        .bind("127.0.0.1:3000")
        .expect("Can not bind to '127.0.0.1:3000'")
        .run()
        .unwrap();
}

fn index(_: Authorized) -> HttpResponse {
    HttpResponse::Ok().body("authorized")
}

struct Authorized;

impl FromRequest for Authorized {
    type Error = Error;
    type Future = Result<Self, Error>;
    type Config = ();

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if is_authorized(req) {
            Ok(Authorized)
        } else {
            Err(ErrorUnauthorized("not authorized"))?
        }
    }
}

fn is_authorized(req: &HttpRequest) -> bool {
    if let Some(value) = req.headers().get("authorized") {
        // actual implementation that checks header here
        dbg!(value);
        true
    } else {
        false
    }
}

This code yields:

$ curl localhost:3000
not authorized⏎
$ curl localhost:3000 -H 'Authorized: i am root'
authorized⏎

You could probably do something in the same lines with middlewares, but I have not got my head around the middleware abstraction. Also, you might want to provide useful information to the handlers, like username:

struct Authorized {
    username: String
}