Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to retrieve a readable session in middleware? #22

Closed
avdb13 opened this issue Dec 13, 2022 · 11 comments
Closed

How to retrieve a readable session in middleware? #22

avdb13 opened this issue Dec 13, 2022 · 11 comments

Comments

@avdb13
Copy link

avdb13 commented Dec 13, 2022

The example on docs.rs cites the following code:

async fn handle(request: Request<Body>) -> Result<Response<Body>, Infallible> {
    let session_handle = request.extensions().get::<SessionHandle>().unwrap();
    let session = session_handle.read().await;
    // Use the session as you'd like.

    Ok(Response::new(Body::empty()))
}

This is what I have:

pub async fn flash<B>(mut req: Request<B>, next: Next<B>) -> Result<impl IntoResponse> {
    let session_handle = req.extensions().get::<SessionHandle>().unwrap();
    let session = session_handle.read().await;

    let payload = session.get::<bool>("signed_in").unwrap_or(false);

    req.extensions_mut().insert(payload);
    Ok(next.run(req).await)
}

image

However, I want to embed state in the Request so that the next handler knows whether the user is logged in or not. I'm using Askama for templating in case this is relevant.

@maxcountryman
Copy link
Owner

You might want to look at how axum-login does this: you'll want to pull the SessionHandle off the request and then can acquire either a readable or writable guard.

@avdb13
Copy link
Author

avdb13 commented Dec 13, 2022

https://github.com/maxcountryman/axum-login/blob/a27fe5e2b18cb1d3faf6590fdcc829d77824fdc3/src/auth.rs#L106
Is this the relevant snippet? I don't seem to have an extract_parts method on my Request. Is this part of the underlying ReqBody?

@maxcountryman
Copy link
Owner

Yes that should be: it's the middleware itself which is hopefully helpful here.

extract_parts is via RequestExt.

@avdb13
Copy link
Author

avdb13 commented Dec 14, 2022

Thanks, this is what I ended up with:

pub async fn flash<S: Send + 'static>(
    mut req: Request<S>,
    next: Next<S>,
) -> Result<impl IntoResponse> {
    let Extension(session_handle): Extension<SessionHandle> = req.extract_parts().await?;
    let session = session_handle.read().await;
    let payload = session.get::<bool>("signed_in").unwrap_or(false);

    req.extensions_mut().insert(payload);
    Ok(next.run(req).await)
}

It seems like extract_parts takes &mut self, does this extract all parts or just the one matching the type SessionHandle? Dropping SessionHandle in this scope is fine but I want to make sure all other metadata about Request is preserved.

@maxcountryman
Copy link
Owner

It seems like extract_parts takes &mut self, does this extract all parts or just the one matching the type SessionHandle?

That's a good question: I don't know the answer. It might require looking at the implementation more closely (I don't recall if the docs mention this).

@avdb13
Copy link
Author

avdb13 commented Dec 14, 2022

Okay, I ran into another problem. This is what my router looks like:

    let hidden = Router::new()
        .route("/login", get(handlers::get_login).post(handlers::login))
        .route("/signup", get(handlers::get_signup).post(handlers::signup))
        .route("/logout", get(handlers::logout));

    Router::new()
        .merge(SpaRouter::new("/static", "ui/static"))
        .route("/", get(handlers::get_root))
        .nest("/.api", hidden)
        .layer(session_layer)
        .route_layer(middleware::from_fn(flash))
        .layer(TraceLayer::new_for_http())
        .with_state(app)

Whenever I visit get_login I get error: Missing request extension. Does the session_layer get inherited by the child router, hidden?

@maxcountryman
Copy link
Owner

I think your session layer should come before the flash middle, no?

@avdb13
Copy link
Author

avdb13 commented Dec 14, 2022

Yeah I managed to get that far. Now I figured out that my hidden router doesn't have access to my own middleware and probably neither to session_layer.

@avdb13
Copy link
Author

avdb13 commented Dec 29, 2022

Ended up with a deadlock in my POST handler, trying to figure out what happened in gdb I saw a thread dying shortly after logging in (probably the thread holding the Session).

@maxcountryman
Copy link
Owner

Are you drop'ing the Session?

@avdb13
Copy link
Author

avdb13 commented Jan 4, 2023

Sorry for the late reply. Skimmed through #13 before I realized I didn't drop my reader after spawning a writer in a function call where the reader was still in scope.

@avdb13 avdb13 closed this as completed Jan 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants