My clients authorize through a token in the Authorization
header which needs to be checked for each request. If this header is missing or I cannot find a corresponding user, I want to return the HTTP code Unauthorized
, else I want to handle the request normally.
Currently I have a lot of duplicate code because I am checking for this header in every request handler.
The actix docs suggest in the very first paragraph that it is possible to halt request processing to return a response early
.
How can this be achieved?
Since I have not found an example that implements this behavior I tried to come up with my own middleware function, but it won't compile.
I have already boxed the return values in order to overcome the problem of returning two different types (ServiceResponse
and Map
), so the problem asked in How do I conditionally return different types of futures? is not the issue. It is more that I do not know which types with which trait implementations are exactly required as return value for this wrap_fn
function. The ones I have right now do not work.
App::new()
.wrap(Cors::new().allowed_origin("http://localhost:8080"))
.register_data(state.clone())
.service(
web::scope("/routing")
.wrap_fn(|req, srv| {
let unauth: Box<dyn IntoFuture<Item = ServiceResponse>> = Box::new(ServiceResponse::new(req.into_parts().0, HttpResponse::Unauthorized().finish()));
let auth_header = req.headers().get("Authorization");
match auth_header {
None => unauth,
Some(value) => {
let token = value.to_str().unwrap();
let mut users = state.users.lock().unwrap();
let user_state = users.iter_mut().find(|x| x.auth.token == token);
match user_state {
None => unauth,
Some(user) => {
Box::new(srv.call(req).map(|res| res))
}
}
}
}
})
.route("/closest", web::get().to(routing::find_closest))
.route("/fsp", web::post().to(routing::fsp))
.route("/preference", web::get().to(routing::get_preference))
.route("/preference", web::post().to(routing::set_preference))
.route("/find_preference", web::post().to(routing::find_preference))
.route("/reset", web::post().to(routing::reset_data)),
)
.bind("0.0.0.0:8000")
.expect("Can not bind to port 8000")
.run()
.expect("Could not start sever");
There are two errors that I am getting upon compiling.
1.
error[E0191]: the value of the associated types `Future` (from the trait `futures::future::IntoFuture`), `Error` (from the trait `futures::future::IntoFuture`) must be specified
--> src/server/mod.rs:36:41
|
36 | let unauth: Box<dyn IntoFuture<Item = ServiceResponse>> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| associated type `Future` must be specified
| associated type `Error` must be specified
2.
error[E0277]: the trait bound `dyn futures::future::IntoFuture<Item = actix_web::service::ServiceResponse>: futures::future::Future` is not satisfied
--> src/server/mod.rs:35:22
|
35 | .wrap_fn(|req, srv| {
| ^^^^^^^ the trait `futures::future::Future` is not implemented for `dyn futures::future::IntoFuture<Item = actix_web::service::ServiceResponse>`
|
= note: required because of the requirements on the impl of `futures::future::Future` for `std::boxed::Box<dyn futures::future::IntoFuture<Item = actix_web::service::ServiceResponse>>`