Skip to main content

authly_session/
lib.rs

1use async_trait::async_trait;
2use authly_core::{AuthError, Identity};
3use serde::{Deserialize, Serialize};
4
5use std::collections::HashMap;
6use std::sync::Mutex;
7
8#[cfg(feature = "store-sqlx")]
9pub mod sql_store;
10
11#[cfg(feature = "store-sqlx")]
12pub use sql_store::{SqlSessionStore, SqlStore};
13
14#[cfg(feature = "store-redis")]
15pub mod redis_store;
16
17#[cfg(feature = "store-redis")]
18pub use redis_store::RedisStore;
19
20#[derive(Clone, Debug, Serialize, Deserialize)]
21pub struct Session {
22    pub id: String,
23    pub identity: Identity,
24    pub expires_at: chrono::DateTime<chrono::Utc>,
25}
26
27#[async_trait]
28pub trait SessionStore: Send + Sync + 'static {
29    async fn load_session(&self, id: &str) -> Result<Option<Session>, AuthError>;
30    async fn save_session(&self, session: &Session) -> Result<(), AuthError>;
31    async fn delete_session(&self, id: &str) -> Result<(), AuthError>;
32}
33
34#[derive(Default)]
35pub struct MemoryStore {
36    sessions: Mutex<HashMap<String, Session>>,
37}
38
39impl MemoryStore {
40    pub fn new() -> Self {
41        Self::default()
42    }
43}
44
45#[async_trait]
46impl SessionStore for MemoryStore {
47    async fn load_session(&self, id: &str) -> Result<Option<Session>, AuthError> {
48        Ok(self.sessions.lock().unwrap().get(id).cloned())
49    }
50    async fn save_session(&self, session: &Session) -> Result<(), AuthError> {
51        self.sessions
52            .lock()
53            .unwrap()
54            .insert(session.id.clone(), session.clone());
55        Ok(())
56    }
57    async fn delete_session(&self, id: &str) -> Result<(), AuthError> {
58        self.sessions.lock().unwrap().remove(id);
59        Ok(())
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[tokio::test]
68    async fn test_memory_store() {
69        let store = MemoryStore::default();
70        let session = Session {
71            id: "test_id".to_string(),
72            identity: Identity {
73                provider_id: "test".to_string(),
74                external_id: "123".to_string(),
75                email: None,
76                username: None,
77                attributes: HashMap::new(),
78            },
79            expires_at: chrono::Utc::now() + chrono::Duration::hours(1),
80        };
81
82        store.save_session(&session).await.unwrap();
83        let loaded = store.load_session("test_id").await.unwrap().unwrap();
84        assert_eq!(loaded.id, "test_id");
85
86        store.delete_session("test_id").await.unwrap();
87        let loaded = store.load_session("test_id").await.unwrap();
88        assert!(loaded.is_none());
89    }
90}