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

Example of session while using tower_cookies and axum? #7

Closed
SylvainMartel opened this issue Jan 7, 2022 · 6 comments
Closed

Example of session while using tower_cookies and axum? #7

SylvainMartel opened this issue Jan 7, 2022 · 6 comments

Comments

@SylvainMartel
Copy link

See tokio-rs/axum#695

Hi, when using the flash crate in axum, we also have to use the crate tower_cookies too for cookie management. As such, the session example in the axum repo will not work(I remember reading somewhere that tower_cookies kinda override any cookies made by other means?).

Right now, I have no idea how to get current cookies while inside axum FromRequest implementation. When I do a cookies.list()) in the FromRequest implementation, it shows an Empty list even though there are 2 cookies that were created upon the user logging in(I can see them correctly in the browser.)

Having an example of session using tower-cookies would be much appreciated :)

@imbolc
Copy link
Owner

imbolc commented Jan 8, 2022

Hey :) If you see cookies in the browser, cookies.list() should certainly work. Check if middlewares are initialized correctly and are in a meaningful order. Check if you can see these cookies using extractor: async fn handler(cookies: Cookies). If it won't help you can simplify and share your code and I'll check it.

@SylvainMartel
Copy link
Author

SylvainMartel commented Jan 8, 2022

Hi, thanks for the reply. Yes, I can see and grab the cookies normally inside a handler, but not inside a "FromRequest" implementation. I'm no dev, so it might be something trivial that I am missing. :)

This simple route works fine:

async fn greet(
    extract::Path(name): extract::Path<String>,
    cookies: Cookies,
) -> HelloTemplate {
    dbg!(&cookies.list());  //<<<<<- The cookie is seen correctly
    let template = HelloTemplate { name };
    template
}

But if I want to see the cookies through another FromRequest (like the jwt example,or the session example) then I cannot see the cookie from inside that implementation:


async fn greet(
    extract::Path(name): extract::Path<String>,
    cookies: Cookies,
    claim: Claims, //<<<<<<<<<<<<<------- This verifies the jwt token, but since it's inside a cookie I need to get the cookies too
) -> HelloTemplate {
    let template = HelloTemplate { name };
    template
}

pub struct Claims {
    pub sub: String,
    pub role: String,
    pub exp: i64,
}

impl Display for Claims {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Email: {}\nRole: {}", self.sub, self.role)
    }
}

#[async_trait]
impl<B> FromRequest<B> for Claims
where
    B: Send,
{
    type Rejection = AuthError;

    async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
        let cookies = Cookies::default(); 
        dbg!(&cookies.list());  // <<<<<<< ---  Empty

       //code to extract token and verify it

        Ok(token_data.claims)
    }
}

and the loading order:

    let app = Router::new()
   //snip all trhe routes
        .layer(
            ServiceBuilder::new()
                .layer(CookieManagerLayer::new())
                .layer(AddExtensionLayer::new(shared_state))
                .layer(axum_flash::layer(key).with_cookie_manager()),
        );

To get an extension inside the FromRequest, we usually have to use something like let Extension(user_state) = Extension::<Arc<UserState>>::from_request(req) but I cannot find a way to make it work with CookieManagerLayer.

@imbolc
Copy link
Owner

imbolc commented Jan 8, 2022

I'd say it's rather courageous to use rust not being a dev 🙇

The problem is in Cookies::default() - it knows nothing about headers, so it just creates a new empty jar. I've added an example how to use already initialized one instead: https://github.com/imbolc/tower-cookies/blob/main/examples/counter-extractor.rs#L24-L33

@SylvainMartel
Copy link
Author

That did it :) Huge thanks! I learned a new way to call extensions too(and indeed, reading the RequestParts doc clearly shows it's part of that struct.)

Yes, Rust can be a bit daunting for a hobbyist like me, but somehow, it's what click the most for me syntax wise. Before moving to pure electronic and then IT, I learned basic programming in college in the mid-90's with Quick Basic, Assembly and C, and Rust feels just "right" for me with that background. What I lack is all the years of experience devs have reading API docs, or all the coding patterns you learn as you go on. I did a small gym software for a friend in python(django) and was looking at another language to make it faster, so I tired GO, but I simply cannot wrap my head around the signature of a function in GO. The brain refuses to compute it :P So Rust it is. Even with the struggles, I like it alot, and the fact that there isn't really any fully mature framework yet forces me to learn what's under the hood. I just wish there was a complete book on what "subsystems" you have to make for a modern web app. The closest I have found so far is "Let's Go" by Alex Edwards.

But enough babbling, time to go extract the info from that cookie :D

@imbolc
Copy link
Owner

imbolc commented Jan 9, 2022

I'd agree completely, Rust seem to be the best mainstream language right now. The learning curve could be quite overwhelming though :) But after I lower my anticipations and take my time, it always feels more than rewarding.

Have you seen this book: https://www.zero2prod.com/

@SylvainMartel
Copy link
Author

SylvainMartel commented Jan 9, 2022

Have you seen this book: https://www.zero2prod.com/

I just pulled the triggeron that one and finally got it. Chapter 10 is about session so it is indeed a good time to get it :)

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