sa_token_core/
temp_token.rs1use std::sync::Arc;
6use std::time::Duration;
7
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10use sha2::{Digest, Sha256};
11
12use crate::dao::SaTokenDao;
13use crate::error::{SaTokenError, SaTokenResult};
14use crate::token::random_hex;
15use crate::util::StpUtil;
16
17pub const DEFAULT_NAMESPACE: &str = "default";
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct TempTokenRecord {
25 pub value: serde_json::Value,
28 pub namespace: String,
31 pub expire_at: Option<DateTime<Utc>>,
34}
35
36#[derive(Clone)]
39pub struct TempTokenManager {
40 dao: Arc<SaTokenDao>,
41}
42
43impl std::fmt::Debug for TempTokenManager {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.write_str("TempTokenManager { .. }")
46 }
47}
48
49impl TempTokenManager {
50 pub fn new(dao: Arc<SaTokenDao>) -> Self {
53 Self { dao }
54 }
55
56 fn ttl(timeout_secs: i64) -> SaTokenResult<Option<Duration>> {
57 if timeout_secs == 0 {
58 return Err(SaTokenError::ConfigError(
59 "temp token timeout must not be 0".into(),
60 ));
61 }
62 if timeout_secs < 0 {
63 Ok(None)
64 } else {
65 Ok(Some(Duration::from_secs(timeout_secs as u64)))
66 }
67 }
68
69 fn expire_at(timeout_secs: i64) -> Option<DateTime<Utc>> {
70 if timeout_secs < 0 {
71 None
72 } else {
73 Some(Utc::now() + chrono::Duration::seconds(timeout_secs))
74 }
75 }
76
77 fn index_digest(value: &str) -> String {
78 let mut h = Sha256::new();
79 h.update(value.as_bytes());
80 hex::encode(h.finalize())
81 }
82
83 pub async fn create(
89 &self,
90 namespace: &str,
91 value: serde_json::Value,
92 timeout_secs: i64,
93 record_index: bool,
94 ) -> SaTokenResult<String> {
95 if namespace.is_empty() {
96 return Err(SaTokenError::ConfigError(
97 "temp token namespace must not be empty".into(),
98 ));
99 }
100 let ttl = Self::ttl(timeout_secs)?;
101 let record = TempTokenRecord {
102 value: value.clone(),
103 namespace: namespace.to_string(),
104 expire_at: Self::expire_at(timeout_secs),
105 };
106 let mut token = String::new();
109 for _ in 0..12 {
110 let candidate = random_hex(32)?;
111 let key = self.dao.keys().temp_token(namespace, &candidate);
112 let raw = self.dao.encode(&record)?;
113 if self.dao.set_if_absent(&key, &raw, ttl).await? {
114 token = candidate;
115 break;
116 }
117 }
118 if token.is_empty() {
119 return Err(SaTokenError::ConfigError(
120 "failed to allocate a unique temp token".into(),
121 ));
122 }
123 if record_index {
124 if let Some(s) = value.as_str() {
125 let ik = self
126 .dao
127 .keys()
128 .temp_index(namespace, &Self::index_digest(s));
129 self.dao.set_string(&ik, &token, ttl).await?;
130 }
131 }
132 Ok(token)
133 }
134
135 pub async fn parse(&self, namespace: &str, token: &str) -> SaTokenResult<TempTokenRecord> {
138 if token.is_empty() {
139 return Err(SaTokenError::TempTokenNotFound);
140 }
141 let key = self.dao.keys().temp_token(namespace, token);
142 let rec: TempTokenRecord = self
143 .dao
144 .get_object(&key)
145 .await?
146 .ok_or(SaTokenError::TempTokenNotFound)?;
147 if let Some(exp) = rec.expire_at {
148 if Utc::now() > exp {
149 let _ = self.dao.delete(&key).await;
150 return Err(SaTokenError::TempTokenExpired);
151 }
152 }
153 Ok(rec)
154 }
155
156 pub async fn find_token(&self, namespace: &str, value: &str) -> SaTokenResult<String> {
159 let ik = self
160 .dao
161 .keys()
162 .temp_index(namespace, &Self::index_digest(value));
163 self.dao
164 .get_string(&ik)
165 .await?
166 .ok_or(SaTokenError::TempTokenNotFound)
167 }
168
169 pub async fn delete(&self, namespace: &str, token: &str) -> SaTokenResult<()> {
172 let key = self.dao.keys().temp_token(namespace, token);
173 if let Ok(Some(rec)) = self.dao.get_object::<TempTokenRecord>(&key).await {
174 if let Some(s) = rec.value.as_str() {
175 let ik = self
176 .dao
177 .keys()
178 .temp_index(namespace, &Self::index_digest(s));
179 let _ = self.dao.delete(&ik).await;
180 }
181 }
182 self.dao.delete(&key).await
183 }
184}
185
186pub async fn create_default(value: impl Into<String>, timeout_secs: i64) -> SaTokenResult<String> {
189 let manager = StpUtil::try_get_manager()?;
190 TempTokenManager::new(manager.dao().clone())
191 .create(
192 DEFAULT_NAMESPACE,
193 serde_json::Value::String(value.into()),
194 timeout_secs,
195 false,
196 )
197 .await
198}
199
200pub async fn parse_default(token: &str) -> SaTokenResult<TempTokenRecord> {
202 let manager = StpUtil::try_get_manager()?;
203 TempTokenManager::new(manager.dao().clone())
204 .parse(DEFAULT_NAMESPACE, token)
205 .await
206}
207
208pub async fn delete_default(token: &str) -> SaTokenResult<()> {
210 let manager = StpUtil::try_get_manager()?;
211 TempTokenManager::new(manager.dao().clone())
212 .delete(DEFAULT_NAMESPACE, token)
213 .await
214}