axum_security/cookie/store/
mod.rs1mod memory;
2
3use std::{pin::Pin, sync::Arc};
4
5use axum::response::{IntoResponse, Response};
6pub use memory::MemStore;
7
8use crate::cookie::{CookieSession, SessionId};
9
10pub trait CookieStore: Send + Sync + 'static {
11 type State: Send + Sync + 'static;
12 type Error: IntoResponse + Send + 'static;
13
14 fn spawn_maintenance_task(&self) -> bool {
15 true
16 }
17
18 fn store_session(
19 &self,
20 session: CookieSession<Self::State>,
21 ) -> impl Future<Output = Result<(), Self::Error>> + Send;
22
23 fn remove_session(
24 &self,
25 id: &SessionId,
26 ) -> impl Future<Output = Result<Option<CookieSession<Self::State>>, Self::Error>> + Send;
27
28 fn load_session(
29 &self,
30 id: &SessionId,
31 ) -> impl Future<Output = Result<Option<CookieSession<Self::State>>, Self::Error>> + Send;
32
33 fn remove_before(&self, deadline: u64) -> impl Future<Output = Result<(), Self::Error>> + Send;
34}
35
36#[allow(clippy::type_complexity)]
37trait DynStore<S>: Send + Sync + 'static {
38 fn spawn_maintenance_task(&self) -> bool;
39
40 fn store_session(
41 &self,
42 session: CookieSession<S>,
43 ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>>;
44
45 fn remove_session<'a>(
46 &'a self,
47 id: &'a SessionId,
48 ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<S>>, Response>> + Send + 'a>>;
49
50 fn load_session<'a>(
51 &'a self,
52 id: &'a SessionId,
53 ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<S>>, Response>> + Send + 'a>>;
54
55 fn remove_before(
56 &self,
57 deadline: u64,
58 ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>>;
59}
60
61impl<T> DynStore<T::State> for T
62where
63 T: CookieStore,
64{
65 fn spawn_maintenance_task(&self) -> bool {
66 <T as CookieStore>::spawn_maintenance_task(self)
67 }
68
69 fn store_session(
70 &self,
71 session: CookieSession<T::State>,
72 ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>> {
73 Box::pin(async move {
74 <T as CookieStore>::store_session(self, session)
75 .await
76 .map_err(IntoResponse::into_response)
77 })
78 }
79
80 fn remove_session<'a>(
81 &'a self,
82 id: &'a SessionId,
83 ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<T::State>>, Response>> + Send + 'a>>
84 {
85 Box::pin(async move {
86 <T as CookieStore>::remove_session(self, id)
87 .await
88 .map_err(IntoResponse::into_response)
89 })
90 }
91
92 fn load_session<'a>(
93 &'a self,
94 id: &'a SessionId,
95 ) -> Pin<Box<dyn Future<Output = Result<Option<CookieSession<T::State>>, Response>> + Send + 'a>>
96 {
97 Box::pin(async move {
98 <T as CookieStore>::load_session(self, id)
99 .await
100 .map_err(IntoResponse::into_response)
101 })
102 }
103
104 fn remove_before(
105 &self,
106 deadline: u64,
107 ) -> Pin<Box<dyn Future<Output = Result<(), Response>> + Send + '_>> {
108 Box::pin(async move {
109 <T as CookieStore>::remove_before(self, deadline)
110 .await
111 .map_err(IntoResponse::into_response)
112 })
113 }
114}
115
116pub(crate) struct ErasedStore<S>(Arc<dyn DynStore<S>>);
117
118impl<S: 'static> ErasedStore<S> {
119 pub fn new(store: S) -> ErasedStore<S::State>
120 where
121 S: CookieStore,
122 {
123 ErasedStore(Arc::new(store))
124 }
125
126 pub fn spawn_maintenance_task(&self) -> bool {
127 self.0.spawn_maintenance_task()
128 }
129
130 pub async fn store_session(&self, session: CookieSession<S>) -> Result<(), Response> {
131 self.0.store_session(session).await
132 }
133
134 pub async fn remove_session(
135 &self,
136 id: &SessionId,
137 ) -> Result<Option<CookieSession<S>>, Response> {
138 self.0.remove_session(id).await
139 }
140
141 pub async fn load_session(&self, id: &SessionId) -> Result<Option<CookieSession<S>>, Response> {
142 self.0.load_session(id).await
143 }
144
145 pub async fn remove_before(&self, deadline: u64) -> Result<(), Response> {
146 self.0.remove_before(deadline).await
147 }
148}
149
150impl<S> Clone for ErasedStore<S> {
151 fn clone(&self) -> Self {
152 ErasedStore(self.0.clone())
153 }
154}