'actix-web: Add data to request in middleware
I am learning actix-web, I parsed jwt in middleware, I want to pass the data in jwt to the controller that parses to handle this request, but I don't know how to do it
my middleware:
use actix_web::{error::ErrorUnauthorized, Error};
use std::future::{ready, Ready};
use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform};
use futures_util::future::LocalBoxFuture;
pub struct JWTAuth;
impl<S, B> Transform<S, ServiceRequest> for JWTAuth
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = JWTAuthHiMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(JWTAuthHiMiddleware {
service,
verification_path: vec!["/api"],
noverification_path: vec!["/api/auth"],
}))
}
}
pub struct JWTAuthHiMiddleware<S> {
service: S,
verification_path: Vec<&'static str>,
noverification_path: Vec<&'static str>,
}
impl<S, B> JWTAuthHiMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
fn is_need_verification(&self, path: &str) -> bool {
self.verification_path
.iter()
.any(|&vp| path.starts_with(vp))
&& !self
.noverification_path
.iter()
.any(|&vp| path.starts_with(vp))
}
}
impl<S, B> Service<ServiceRequest> for JWTAuthHiMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
if self.is_need_verification(req.path()) {
let authorization = req.headers().get("Authorization");
if authorization.is_none() {
return Box::pin(async { Err(ErrorUnauthorized("err")) });
}
let authorization = authorization.unwrap().to_str();
if authorization.is_err() {
return Box::pin(async { Err(ErrorUnauthorized("err")) });
}
let authorization = authorization.unwrap();
let token = &authorization[7..]; // 'Bearer ' + token
let token_data = crate::utils::jwt::Claims::decode(token);
if let Err(err) = token_data {
return Box::pin(async { Err(ErrorUnauthorized(err)) });
}
let token_data = token_data.unwrap();
// I need to pass this user_id to the next Handle
println!("user_id: {}", &token_data.claims.user_id);
}
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
Ok(res)
})
}
}
I want to get this user_id data in the controller
#[get("/user")]
pub async fn list(req: actix_web::HttpRequest, pool: web::Data<DbPool>) -> HttpResult {
// This is the way I guess, the right way I don't know how to do it
req.user_id;
Ok(HttpResponse::Ok().json(req.user_id))
}
Solution 1:[1]
Refer to this example
https://github.com/actix/examples/tree/master/middleware/middleware-ext-mut
let token_data = token_data.unwrap();
req.extensions_mut().insert(token_data.claims);
pub async fn list(claims: Option<web::ReqData<Claims>>, pool: web::Data<DbPool>) -> HttpResult {
if let Some(claims) = claims {
log::info!("user_id: {:?}", claims.user_id);
}
...
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | januw a |
