From 33509c461808bff8a464df74d93f2e16896a584a Mon Sep 17 00:00:00 2001 From: genusistimelord Date: Mon, 23 Oct 2023 14:00:44 -0400 Subject: [PATCH] Updated to axum_session 0.8.0, added advanced features --- CHANGELOG.md | 9 +++ Cargo.toml | 7 +- examples/NoPoolType/Cargo.toml | 2 +- examples/sqlx-example/Cargo.toml | 2 +- src/service.rs | 5 +- src/session.rs | 111 ++++++++++++++++++++++++++++++- 6 files changed, 126 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 302a477..9532914 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## Unreleased + +## 0.8.0 (23. October, 2023) +### Changed +- Updated axum_session to 0.8.0. + +### Added +- Added `AuthStatus`, `AuthSession::is_logged_in()`, `AuthSession::reload_user` and `AuthSession::update_user_expiration`. +- Features locked behind an advanced feature. ## 0.7.0 (4. October, 2023) ### Changed diff --git a/Cargo.toml b/Cargo.toml index d13bb33..9184bdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ [package] name = "axum_session_auth" -version = "0.7.0" +version = "0.8.0" authors = ["Andrew Wheeler "] description = "Library to Provide a User Authentication and privilege Token Checks. It requires the Axum_Session library." edition = "2021" @@ -39,6 +39,7 @@ surrealdb-mem = ["axum_session/surrealdb-mem"] key-store = ["axum_session/key-store"] rest_mode = ["axum_session/rest_mode"] mongo = ["axum_session/mongo"] +advanced = ["axum_session/advanced"] [dependencies] axum-core = "0.3.4" @@ -60,9 +61,9 @@ serde = "1.0.188" #path = "C:/Sources/AxumSession" #git = "https://github.com/AscendingCreations/AxumSessions.git" #branch = "axum0.6" -version = "0.7.0" +version = "0.8.0" default-features = false [package.metadata.docs.rs] -features = ["sqlite-rustls","mysql-rustls","redis-db", "surrealdb-rocksdb", "surrealdb-mem"] +features = ["sqlite-rustls","mysql-rustls","redis-db", "surrealdb-rocksdb", "surrealdb-mem", "advanced"] rustdoc-args = ["--document-private-items"] diff --git a/examples/NoPoolType/Cargo.toml b/examples/NoPoolType/Cargo.toml index 4c3eb5b..f2d75fd 100644 --- a/examples/NoPoolType/Cargo.toml +++ b/examples/NoPoolType/Cargo.toml @@ -21,7 +21,7 @@ anyhow = "1.0.71" serde = "1.0.167" [dependencies.axum_session] -version = "0.7.0" +version = "0.8.0" features = ["sqlite-rustls"] [dependencies.axum_session_auth] diff --git a/examples/sqlx-example/Cargo.toml b/examples/sqlx-example/Cargo.toml index caa4131..c1c617e 100644 --- a/examples/sqlx-example/Cargo.toml +++ b/examples/sqlx-example/Cargo.toml @@ -21,7 +21,7 @@ anyhow = "1.0.71" serde = "1.0.167" [dependencies.axum_session] -version = "0.7.0" +version = "0.8.0" features = ["sqlite-rustls"] [dependencies.axum_session_auth] diff --git a/src/service.rs b/src/service.rs index 947b281..b4b2f03 100644 --- a/src/service.rs +++ b/src/service.rs @@ -81,7 +81,7 @@ where let id = axum_session .get::(&config.session_id) - .map_or(config.anonymous_user_id, Some) + .map_or(config.anonymous_user_id.clone(), Some) .unwrap_or_else(|| Type::default()); let current_user = if id != Type::default() { @@ -123,7 +123,8 @@ where current_user, cache, session: axum_session, - phantom: PhantomData, + pool, + config, }; // Sets a clone of the Store in the Extensions for Direct usage and sets the Session for Direct usage diff --git a/src/session.rs b/src/session.rs index 8247126..68b4d32 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,11 +1,15 @@ -use crate::AuthCache; +#[cfg(feature = "advanced")] +use crate::AuthUser; +use crate::{AuthCache, AuthConfig}; use anyhow::Error; use async_trait::async_trait; use axum_core::extract::FromRequestParts; use axum_session::{DatabasePool, Session}; +#[cfg(feature = "advanced")] +use chrono::Utc; use http::{self, request::Parts, StatusCode}; use serde::{de::DeserializeOwned, Serialize}; -use std::{fmt, hash::Hash, marker::PhantomData}; +use std::{fmt, hash::Hash}; /// AuthSession that is generated when a user is routed via Axum /// @@ -23,7 +27,10 @@ where pub current_user: Option, pub session: Session, pub(crate) cache: AuthCache, - pub phantom: PhantomData, + #[allow(dead_code)] + pub(crate) pool: Option, + #[allow(dead_code)] + pub(crate) config: AuthConfig, } #[async_trait] @@ -167,4 +174,102 @@ where self.session.remove("user_auth_session_id"); self.session.renew(); } + + /// Used to check if a long living AuthSession is still logged in, + /// if the user logged out or if the user switched account id's during + /// the last request the AuthSession was created from. This does not check + /// if the session itself is not the same or reloaded. + /// + /// # Examples + /// ```rust no_run + /// auth.is_logged_in(); + /// ``` + /// + #[cfg(feature = "advanced")] + pub fn is_logged_in(&mut self) -> AuthStatus { + if let Some(id) = self.session.get::(&self.config.session_id) { + if id == self.id { + if self.cache.inner.contains_key(&self.id) { + AuthStatus::LoggedIn + } else { + AuthStatus::LoggedOut + } + } else { + AuthStatus::DifferentID + } + } else { + AuthStatus::LoggedOut + } + } + + /// Reloads the user data into current user and cache. + /// + /// # Examples + /// ```rust no_run + /// auth.reload_user().await; + /// ``` + /// + #[cfg(feature = "advanced")] + pub async fn reload_user(&mut self) { + let current_user = User::load_user(self.id.clone(), self.pool.as_ref()) + .await + .ok(); + + if self.config.cache { + let user = if let Some((_id, mut user)) = self.cache.inner.remove(&self.id) { + user.expires = Utc::now() + self.config.max_age; + user.current_user = current_user.clone(); + user + } else { + AuthUser:: { + current_user: current_user.clone(), + expires: Utc::now() + self.config.max_age, + phantom_pool: Default::default(), + phantom_type: Default::default(), + } + }; + + self.cache.inner.insert(self.id.clone(), user); + } + + self.current_user = current_user; + } + + /// Updates the users expiration time so a request will not + /// remove them from the cache. + /// + /// THIS WILL NOT RELOAD THE USERS DATA + /// + /// # Examples + /// ```rust no_run + /// auth.update_user_expiration(); + /// ``` + /// + #[cfg(feature = "advanced")] + pub fn update_user_expiration(&mut self) { + if self.config.cache { + if let Some(mut user) = self.cache.inner.get_mut(&self.id) { + user.expires = Utc::now() + self.config.max_age; + } + } + } +} + +/// Used to display how the users Auth data is compared to what +/// a AuthSessions Data was set as. To ensure nothing changed. +/// +/// # Examples +/// ```rust no_run +/// auth.is_logged_in(); +/// ``` +/// +#[cfg(feature = "advanced")] +pub enum AuthStatus { + /// If the user id did not change and is logged in + LoggedIn, + /// If the users id did not match or got changed internally + /// by another request. + DifferentID, + /// the user is logged out. + LoggedOut, }