I implemented the login function and the function of checking user information in the handler according to the instructions in the document, but it is obviously unreasonable to check the user login status in each handler, so I want to add a middleware to check whether the user is logged in. I added the AuthMiddleware and completed the registration, but in the AuthMiddleware, I can't get the identify
// main.rs
let private_key = actix_web::cookie::Key::generate();
let redis_url = app_config.app.datasource.redis_url;
let redis_store = RedisSessionStore::new(redis_url)
.await
.expect("Failed to create redis conn.");
// create http server
HttpServer::new(move || {
let identity_middleware = IdentityMiddleware::default();
// let identity_middleware = IdentityMiddleware::builder()
// .logout_behaviour(LogoutBehaviour::PurgeSession)
// .login_deadline(login_deadline_seconds)
// .visit_deadline(visit_deadline_seconds)
// .id_key(id_key)
// .login_unix_timestamp_key(login_unix_timestamp_key)
// .last_visit_unix_timestamp_key(last_visit_unix_timestamp_key)
// .build();
let session_middleware = SessionMiddleware::new(redis_store.clone(), private_key.clone());
// let session_middleware = SessionMiddleware::builder(redis_store.clone(), private_key.clone())
// .cookie_http_only(true)
// .cookie_name("X-SESSION".into())
// .cookie_path("/api".into())
// .cookie_same_site(SameSite::Strict)
// .cookie_content_security(CookieContentSecurity::Private)
// .build();
let auth_middleware = AuthMiddleware{ whitelist: whitelist.clone(), };
let default_header_middleware = middleware::DefaultHeaders::new().add(("X-Version", "1.0.0"));
let logger_middleware = Logger::default();
let service = web::scope("/api")
.configure(sys_api::routes::init);
App::new()
.app_data(json_config.clone())
.app_data(web::Data::new(Arc::clone(&context)))
.wrap(auth_middleware)
.wrap(identity_middleware)
.wrap(session_middleware)
.wrap(default_header_middleware)
.wrap(logger_middleware)
.service(service)
})
.apply_settings(&app_config.actix)
.run()
.await
//auth_middleware.rs
use std::future::{ready, Ready};
use actix_web::middleware::Identity;
use actix_web::{dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform}, Error, FromRequest, HttpMessage, HttpResponse};
use actix_web::body::EitherBody;
use futures_util::future::LocalBoxFuture;
use app_base::config::app_config::WhitelistItem;
pub struct AuthMiddleware{
pub whitelist: Vec<WhitelistItem>,
}
impl<S, B> Transform<S, ServiceRequest> for AuthMiddleware
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type InitError = ();
type Transform = InnerAuthMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ready(Ok(InnerAuthMiddleware { service, whitelist: self.whitelist.clone() }))
}
}
pub struct InnerAuthMiddleware<S> {
service: S,
whitelist: Vec<WhitelistItem>
}
impl<S, B> Service<ServiceRequest> for InnerAuthMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, request: ServiceRequest) -> Self::Future {
// check whitelist
let whitelist = &self.whitelist;
let request_path = request.path().to_string();
let request_method = request.method().to_string();
let is_whitelisted = whitelist.iter().any(|item| {
item.path == request_path && item.method.eq_ignore_ascii_case(&request_method)
});
if is_whitelisted {
let res = self.service.call(request);
Box::pin(async move {
// forwarded responses map to "left" body
res.await.map(ServiceResponse::map_into_left_body)
})
}else{
let identity = request.extensions().get::<Identity>().cloned();
println!("identity: {:?}", identity);
if let Some(identity) = identity {
let res = self.service.call(request);
Box::pin(async move {
// forwarded responses map to "left" body
res.await.map(ServiceResponse::map_into_left_body)
})
} else {
let (request, _pl) = request.into_parts();
let response = HttpResponse::Unauthorized()
.finish()
.map_into_right_body();
return Box::pin(async { Ok(ServiceResponse::new(request, response)) });
}
}
}
}
Print log after calling the interface >> identity: None
Rust version (output of rustc -V):
actix-web = { version = "4.8.0" }
actix-session = { version = "0.9.0", features = ["redis-rs-session"] }
actix-identity = "0.7.1"
actix-settings = "0.7.1"
actix-service = "2.0.2"
https://docs.rs/actix-identity/latest/actix_identity/
I implemented the login function and the function of checking user information in the handler according to the instructions in the document, but it is obviously unreasonable to check the user login status in each handler, so I want to add a middleware to check whether the user is logged in. I added the AuthMiddleware and completed the registration, but in the AuthMiddleware, I can't get the identify
Print log after calling the interface >> identity: None
rustc -V
): actix-web = { version = "4.8.0" } actix-session = { version = "0.9.0", features = ["redis-rs-session"] } actix-identity = "0.7.1" actix-settings = "0.7.1" actix-service = "2.0.2"