use std::future::{ready, Ready}; use actix_web::{ body::EitherBody, dev::{self, Service, ServiceRequest, ServiceResponse, Transform}, http, Error, HttpResponse, }; use futures_util::future::LocalBoxFuture; pub struct CheckLogin; impl Transform for CheckLogin where S: Service, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse>; type Error = Error; type InitError = (); type Transform = CheckLoginMiddleware; type Future = Ready>; fn new_transform(&self, service: S) -> Self::Future { ready(Ok(CheckLoginMiddleware { service })) } } pub struct CheckLoginMiddleware { service: S, } impl Service for CheckLoginMiddleware where S: Service, Error = Error>, S::Future: 'static, B: 'static, { type Response = ServiceResponse>; type Error = Error; type Future = LocalBoxFuture<'static, Result>; dev::forward_ready!(service); fn call(&self, request: ServiceRequest) -> Self::Future { // Change this to see the change in outcome in the browser. // Usually this boolean would be acquired from a password check or other auth verification. let is_logged_in = false; // Don't forward to `/login` if we are already on `/login`. if !is_logged_in && request.path() != "/login" { let (request, _pl) = request.into_parts(); let response = HttpResponse::Found() .insert_header((http::header::LOCATION, "/login")) .finish() // constructed responses map to "right" body .map_into_right_body(); return Box::pin(async { Ok(ServiceResponse::new(request, response)) }); } let res = self.service.call(request); Box::pin(async move { // forwarded responses map to "left" body res.await.map(ServiceResponse::map_into_left_body) }) } }