AscendingCreations / AxumSessionAuth

Library to Provide a User Authentication and privilege Token Checks.
MIT License
111 stars 11 forks source link

Issue with Saving Sessions in SurrealDB: Missing Sessions Table #36

Closed NCura closed 3 weeks ago

NCura commented 3 weeks ago

Hello,

I'm having trouble using the AxumSessionAuth crate with SurrealDB. I followed the example from the GitHub repo, adding simple_logger and logs crates. In the main function, I initialized the logger like this:

simple_logger::init_with_level(log::Level::Debug).expect("Couldn't initialize logging");

When I run the program and navigate to /, I see the following log output:

2024-10-22T17:10:18.917Z INFO  [axum_session::service] Session 4b6f3ce7-c71f-40e4-be64-69caf9c0fd48 did not exist in Database. So it was Recreated.
2024-10-22T17:10:18.917Z DEBUG [axum_session_auth::service] loading user id: 1 from load_user
2024-10-22T17:10:18.919Z INFO  [axum_session::service] Session id 4b6f3ce7-c71f-40e4-be64-69caf9c0fd48: was saved to the database.

Then I visit /login:

2024-10-22T17:10:27.334Z DEBUG [axum_session_auth::service] user id: 1 found in cache
2024-10-22T17:10:27.336Z INFO  [axum_session::service] Session id f1f21a2c-2841-4879-b852-2b89dfa032dc: was saved to the database.

And after navigating to /perm:

2024-10-22T17:10:41.093Z DEBUG [axum_session_auth::service] loading user id: 2 from load_user

Now, every time I refresh any page, I repeatedly see:

2024-10-22T17:10:42.947Z DEBUG [axum_session_auth::service] user id: 2 found in cache
2024-10-22T17:10:43.850Z DEBUG [axum_session_auth::service] user id: 2 found in cache
2024-10-22T17:10:44.386Z DEBUG [axum_session_auth::service] user id: 2 found in cache
2024-10-22T17:10:51.104Z DEBUG [axum_session_auth::service] user id: 2 found in cache

In the main function, the SessionConfig is created like this:

let session_config = SessionConfig::default().with_table_name("test_table");`

However, upon checking SurrealDB, I don't see any table named test_table for storing sessions—only the users and user_permissions tables are present. In the past, using AxumSessionAuth with MySQL, a session table would be automatically created.

Am I missing something here? How can I ensure sessions are saved to the database properly?

Thank you for your help!

NCura commented 3 weeks ago

I created a project based on the sqlx-example, and after switching from SQLite to MySQL (since I'm more comfortable with it), adding logging, and running the server, I observed the following behavior:

2024-10-22T20:21:24.366Z DEBUG [sqlx::query] summary="CREATE TABLE IF NOT …" db.statement="\n\nCREATE TABLE IF NOT EXISTS test_table (\n  id VARCHAR(128) NOT NULL PRIMARY KEY,\n  expires BIGINT NULL,\n  session TEXT NOT NULL\n)\n" rows_affected=0 rows_returned=0 elapsed=113.39µs elapsed_secs=0.00011339

As expected, the session table was created successfully. Navigating to /, I then saw:

2024-10-22T20:27:38.429Z DEBUG [sqlx::query] summary="INSERT INTO test_table (id, …" db.statement="\n\nINSERT INTO\n  test_table (id, session, expires)\nSELECT\n  ?,\n  ?,\n  ? ON DUPLICATE KEY\nUPDATE\n  expires =\nVALUES\n(expires),\n  session =\nVALUES\n(session)\n" rows_affected=2 rows_returned=0 elapsed=5.531823ms elapsed_secs=0.005531823
2024-10-22T20:27:38.429Z INFO  [axum_session::service] Session id 31b957e5-3cac-4246-9fcd-1770cb1b7e0f: was saved to the database.

The sessions were correctly stored in the database, and after restarting the server, I remained logged in, confirming session persistence.

However, this behavior contrasts with the SurrealDB example, where no session table was created and session persistence did not work. It seems something is preventing the session table from being created in the SurrealDB case.

genusistimelord commented 3 weeks ago

surreal is a bit different. it creates tables differently than how normal sql does it. in surrealdb https://github.com/AscendingCreations/AxumSession/blob/main/databases/surreal/src/lib.rs#L114 this creates and adds a row to the table.

https://github.com/AscendingCreations/AxumSession/blob/main/databases/surreal/src/lib.rs#L129 would retrieve that Row if the session cache no longer contained that data but it is located in the session still.

if you run the load command on surrealdb it should display whats within that table. If it does then it means the table exists. just it might not Exist the same way you would expect like in SQL.

NCura commented 3 weeks ago

Thank you for pointing out those functions. I've done some debugging in the perm() function, where I now call the load with the session ID as follows everytime that I go to /perm:

let session_id = &auth.session.get_session_id();
auth.session
    .clone()
    .get_store()
    .client
    .as_ref()
    .unwrap()
    .load(&session_id.inner(), "test_table")
    .await
    .unwrap();

I also modified the store and load functions to add logging. After running cargo run and navigating through /, /login, and /perm, the following output was generated:

     Running `target/debug/axum_auth`
2024-10-23T13:52:56.887Z DEBUG [tungstenite::handshake::client] Client handshake done.

--> load called with:
   id: fafb2d28-e75e-4fb2-8f68-1aceba774e00
   table: test_table
--> Response1: Response { client: Surreal { router: OnceLock(Router { sender: Sender { .. }, last_id: 6, features: {LiveQueries} }), engine: PhantomData<surrealdb::api::engine::any::Any> }, results: {0: (Stats { execution_time: Some(59.481µs) }, Ok(Array(Array([]))))}, live_queries: {} }
--> Response3: Ok(None)
--> Response2: None
--> load done

2024-10-23T13:52:58.716Z INFO  [axum_session::service] Session fafb2d28-e75e-4fb2-8f68-1aceba774e00 did not exist in Database. So it was Recreated.
2024-10-23T13:52:58.716Z DEBUG [axum_session_auth::service] loading user id: 1 from load_user

--> store called with:
   id:fafb2d28-e75e-4fb2-8f68-1aceba774e00
   session: {"data":{},"longterm":false}
   table: test_table
--> Response: Response { client: Surreal { router: OnceLock(Router { sender: Sender { .. }, last_id: 9, features: {LiveQueries} }), engine: PhantomData<surrealdb::api::engine::any::Any> }, results: {0: (Stats { execution_time: Some(19.256µs) }, Ok(Array(Array([]))))}, live_queries: {} }
--> store done

2024-10-23T13:52:58.719Z INFO  [axum_session::service] Session id fafb2d28-e75e-4fb2-8f68-1aceba774e00: was saved to the database.
2024-10-23T13:53:00.405Z DEBUG [axum_session_auth::service] user id: 1 found in cache

--> store called with:
   id:c9224f46-9cf5-4d1a-920f-78852753d317
   session: {"data":{"user_auth_session_id":"2"},"longterm":false}
   table: test_table
--> Response: Response { client: Surreal { router: OnceLock(Router { sender: Sender { .. }, last_id: 12, features: {LiveQueries} }), engine: PhantomData<surrealdb::api::engine::any::Any> }, results: {0: (Stats { execution_time: Some(41.617µs) }, Ok(Array(Array([]))))}, live_queries: {} }
--> store done

2024-10-23T13:53:00.407Z INFO  [axum_session::service] Session id c9224f46-9cf5-4d1a-920f-78852753d317: was saved to the database.
2024-10-23T13:53:01.369Z DEBUG [axum_session_auth::service] loading user id: 2 from load_user

--> load called with:
   id: c9224f46-9cf5-4d1a-920f-78852753d317
   table: test_table
--> Response1: Response { client: Surreal { router: OnceLock(Router { sender: Sender { .. }, last_id: 15, features: {LiveQueries} }), engine: PhantomData<surrealdb::api::engine::any::Any> }, results: {0: (Stats { execution_time: Some(47.96µs) }, Ok(Array(Array([]))))}, live_queries: {} }
--> Response2: Ok(None)
--> Response3: None
--> load done

As we can see, the store response confirms that nothing is being saved. This is further verified by the subsequent load call, which returns None.

I have submitted a PR that introduces a potential fix for this issue. After applying the fix, here is the new output for the load function:

--> load called with:
   id: 2dc919bb-8e4a-45ee-88a4-276085c23adf
   table: test_table
--> Response1: Response { client: Surreal { router: OnceLock(Router { sender: Sender { .. }, last_id: 51, features: {LiveQueries} }), engine: PhantomData<surrealdb::api::engine::any::Any> }, results: {0: (Stats { execution_time: Some(94.648µs) }, Ok(Array(Array([Object(Object({"sessionstore": Strand(Strand("{\"data\":{\"user_auth_session_id\":\"2\"},\"longterm\":false}"))}))]))))}, live_queries: {} }
--> Response2: Ok(Some("{\"data\":{\"user_auth_session_id\":\"2\"},\"longterm\":false}"))
--> Response3: Some("{\"data\":{\"user_auth_session_id\":\"2\"},\"longterm\":false}")
--> load done

With this change, everything appears to be working as expected.