poem-web / poem

A full-featured and easy-to-use web framework with the Rust programming language.
Apache License 2.0
3.5k stars 283 forks source link

Correct usage of `CookieJar`, `private` and `private_with_key` #838

Closed josefcs closed 3 months ago

josefcs commented 3 months ago

I am having some troubles retrieving the private value from a CookieJar. As far as I understand it, the correct way to use the PrivateCookieJar is:

  1. Register the CookieJarManager middleware with a key
  2. Extract a CookieJar in the request
  3. call the private() method
  4. Set the value

Now, this works fine when setting the cookie. I controlled it and the cookie was set in the header.

Server::new(TcpListener::bind("0.0.0.0:8000"))
    .run(
        Route::new()
            .nest("/api", api_service)
            .nest("/openapi.json", spec)
            .with(CookieJarManager::with_key(CookieKey::from(&key_bytes))),
    )
    .await

and the endpoint:

async fn login(
    &self,
    cookie_jar: &CookieJar,
    login_request: Json<AdminLoginRequest>,
) -> Result<Json<String>> {
    if let Some(token) = self
        .auth_service
        .authenticate_admin(&login_request.username, &login_request.password)
        .await
    {
        cookie_jar.private().add(Cookie::new("Authorization", token.token));
        Ok(Json(token.expires_at.to_string()))
    } else {
        let error_response = Response::builder()
            .status(StatusCode::UNAUTHORIZED)
            .body("Invalid username or password")
            .into();
        Err(Error::from_response(error_response))
    }
}

But now, this code won't work (the cookie is None):

async fn check_login(&self, cookie_jar: &CookieJar) -> Result<Json<String>> {
    let auth = cookie_jar.private().get("Authorization");

    if auth.is_none() {
        let error_response = Response::builder()
            .status(StatusCode::UNAUTHORIZED)
            .body("Unauthorized")
            .into();
        return Err(Error::from_response(error_response));
    }

    let auth_cookie = auth.unwrap();

    Ok(Json(auth_cookie.to_string()))
}

However, if I provide the key manually, it works.

let auth = cookie_jar.private_with_key(self.my_stored_key).get("Authorization"); // works fine

Am I doing something wrong, or is this a bug? I would prefer, not having to inject the key into als services' constructor, but rather use the private jar from the extractor.

Thanks Josef

josefcs commented 3 months ago

Sorry and nevermind. My testing method was flawed (Visual Studio .http clients). When using postman, the above example works.

Sorry for the fuzz!