1use std::time::Duration;
7
8use crate::error::{SaTokenError, SaTokenResult};
9use crate::manager::SaTokenManager;
10use crate::token::TokenValue;
11
12pub const DEFAULT_SAFE_SERVICE: &str = "";
15
16pub const SAFE_AUTH_VALUE: &str = "ok";
18
19impl SaTokenManager {
20 fn safe_key(&self, token: &str, service: &str) -> String {
21 self.keys().safe(token, service)
22 }
23
24 pub async fn open_safe(
26 &self,
27 token: &TokenValue,
28 service: &str,
29 safe_time: i64,
30 ) -> SaTokenResult<()> {
31 if safe_time < 0 {
32 return Err(SaTokenError::ConfigError(
33 "safe_time must be >= 0".to_string(),
34 ));
35 }
36
37 let ttl = if safe_time == 0 {
38 None
39 } else {
40 Some(Duration::from_secs(safe_time as u64))
41 };
42
43 self.dao
46 .set_string(
47 &self.safe_key(token.as_str(), service),
48 SAFE_AUTH_VALUE,
49 ttl,
50 )
51 .await?;
52
53 self.event_bus
54 .publish(crate::event::SaTokenEvent::open_safe(
55 token.as_str(),
56 service,
57 ))
58 .await;
59
60 Ok(())
61 }
62
63 pub async fn is_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<bool> {
65 if token.as_str().is_empty() {
66 return Ok(false);
67 }
68
69 if !self.is_valid(token).await {
70 return Ok(false);
71 }
72
73 Ok(self
74 .dao
75 .get_string(&self.safe_key(token.as_str(), service))
76 .await?
77 .as_deref()
78 == Some(SAFE_AUTH_VALUE))
79 }
80
81 pub async fn check_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<()> {
83 if !self.is_valid(token).await {
84 return Err(SaTokenError::NotLogin);
85 }
86
87 if !self.is_safe(token, service).await? {
88 return Err(SaTokenError::NotSafe(service.to_string()));
89 }
90
91 let event = crate::event::SaTokenEvent::safe_verify(token.as_str(), service);
92 self.event_bus.publish(event).await;
93
94 Ok(())
95 }
96
97 pub async fn close_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<()> {
99 self.dao
100 .delete(&self.safe_key(token.as_str(), service))
101 .await?;
102
103 self.event_bus
104 .publish(crate::event::SaTokenEvent::close_safe(
105 token.as_str(),
106 service,
107 ))
108 .await;
109
110 Ok(())
111 }
112
113 pub async fn get_safe_time(
115 &self,
116 token: &TokenValue,
117 service: &str,
118 ) -> SaTokenResult<Option<i64>> {
119 match self.dao.ttl(&self.safe_key(token.as_str(), service)).await {
120 Ok(Some(d)) => Ok(Some(d.as_secs() as i64)),
121 Ok(None) => Ok(None),
122 Err(e) => Err(e),
123 }
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::config::SaTokenConfig;
131 use sa_token_storage_memory::MemoryStorage;
132 use std::sync::Arc;
133
134 fn manager() -> SaTokenManager {
135 SaTokenManager::new(Arc::new(MemoryStorage::new()), SaTokenConfig::default())
136 }
137
138 #[tokio::test]
139 async fn open_check_close_safe() {
140 let mgr = manager();
141 let token = mgr.login("u1").await.unwrap();
142 assert!(!mgr.is_safe(&token, DEFAULT_SAFE_SERVICE).await.unwrap());
143 mgr.open_safe(&token, "pay", 120).await.unwrap();
144 assert!(mgr.is_safe(&token, "pay").await.unwrap());
145 mgr.check_safe(&token, "pay").await.unwrap();
146 mgr.close_safe(&token, "pay").await.unwrap();
147 assert!(!mgr.is_safe(&token, "pay").await.unwrap());
148 }
149}