7

I'm trying to write an authentication middleware for my Actix application. When validating the request in the middleware, I make a call to a database to retrieve the necessary user data to validate the incoming request. Once the request has been authorised, I want to be able to pass this user data to the handler as this will allow me to avoid having the query for the same data twice.

I can't find a solution for this. The best suggestion I could find so far was to "set a request extension". There doesn't seem to be any examples for this and there is also too little documentation around this to work out what to do here.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Rob123
  • 895
  • 6
  • 10
  • 1
    Have you seen https://stackoverflow.com/a/63158225/1418750 Or even more comple https://web.archive.org/web/20200811175006if_/https://github.com/Luis-Hebendanz/tagify-backend/blob/master/src/my_identity_service.rs#L217 – Njuguna Mureithi Sep 02 '20 at 14:25
  • Does this answer your question? [How can I make protected routes in actix-web](https://stackoverflow.com/questions/62269278/how-can-i-make-protected-routes-in-actix-web) – mmirate Jul 01 '21 at 00:52

1 Answers1

11

You can pass data from middleware (service) to handler via extensions. First of all you have to insert extension (in service). For ServiceRequest struct is implemented HttpMessage witch hase extensions_mut() function. It must be mutable becouse you will be inserting new extension. It might look something like this:

req.extensions_mut().insert(user);

Then you have to implement FromRequest trait for your data structure.

impl FromRequest for User {
    type Error = actix_web::Error;
    type Future = futures::future::Ready<Result<Self, Self::Error>>;
    type Config = ();

    fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
        match req.extensions().get::<User>() {
            Some(user) => return ok(user.clone()),
            None => return err(actix_web::error::ErrorBadRequest("ups..."))
        };
    }

}

Then you're ready to use it in handler.

pub async fn get_user_handler(user: User) {}
  • really nice answer, thanks! It is worth to mention that `User` must have derived `Clone` – cinatic Aug 30 '21 at 22:04
  • 2
    As of actix-web 3.2.0, there is the [`ReqData`](https://docs.rs/actix-web/3.3.2/actix_web/web/struct.ReqData.html) extractor. So you can use a `ReqData` parameter in your handler instead of implementing `FromRequest` for `User`. – kmdreko Aug 31 '21 at 19:07
  • 1
    Note that the ok and err types come from the "futures" crate on crates.io. Not shown in the example is `use futures::future::{ok, err};` – tedtanner Nov 18 '21 at 21:42