actix / actix-web

Actix Web is a powerful, pragmatic, and extremely fast web framework for Rust.
https://actix.rs
Apache License 2.0
21.6k stars 1.67k forks source link

Middleware example fails with `wrap` because `IntoTransform` blanket impl doesn't take effect #1057

Closed Sushisource closed 5 years ago

Sushisource commented 5 years ago

It's very unclear to me why, but following the example in https://actix.rs/docs/middleware/

and implementing Transform and Service myself, the wrap call fails with IntoTransform not being imeplemented.

My code -- the Error type is not included here, but shouldn't be relevant as far as I can tell. I've confirmed there's no version mismatch weirdness going on. Everything is using consistent versions of actix-web and actix-service.

#[derive(Default)]
pub struct JwtAuth {
    secret: Option<String>,
}

impl<S, B> Transform<S> for JwtAuth
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Transform = JwtAuthMiddleware<S>;
    type InitError = ();
    type Future = FutureResult<Self::Transform, Self::InitError>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(JwtAuthMiddleware {
            service,
            secret: self.secret.clone(),
        })
    }
}

pub struct JwtAuthMiddleware<S> {
    service: S,
    secret: Option<String>,
}

impl<S, B> Service for JwtAuthMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Either<FutureResult<Self::Response, Error>, S::Future>;

    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
        self.service.poll_ready()
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        // If secret exists, check if token is valid, erroring out the request early if it isn't.
        if let Some(secret) = &self.secret {
           // Code elided here
           return Either::A(err(autherr));          
        }
        // Auth worked. Call the route handler as normal.
        Either::B(self.service.call(req))
    }
}
fafhrd91 commented 5 years ago

What error do you get?

Sushisource commented 5 years ago

The error:

error[E0277]: the trait bound `web_server::auth::JwtAuth: actix_service::transform::IntoTransform<_,
actix_web::app_service::AppRouting>` is not satisfied
   --> ap-api/src/main.rs:109:20
    |
109 |         App::new().wrap(jwt_auther).configure(|c| {
    |                    ^^^^ the trait `actix_service::transform::IntoTransform<_, actix_web::app_service::AppRouting>` is not implemented for `web_server::auth::JwtAuth`

error: aborting due to previous error
fafhrd91 commented 5 years ago

Strange. Is your code available anywhere? I’d like to try myself

fafhrd91 commented 5 years ago

i need reproducible example, re-open if you get one