5

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
  • 326,504
  • 69
  • 892
  • 1,159
Rob123
  • 645
  • 5
  • 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

8

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
  • 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