1use std::sync::Arc;
9
10use crate::disable;
11use crate::error::SaTokenResult;
12use crate::keys::SaKeys;
13use crate::manager::SaTokenManager;
14use crate::session::{SaSession, SaTerminalInfo};
15use crate::token::TokenValue;
16
17#[derive(Clone)]
20pub struct SaLogic {
21 login_type: Arc<str>,
22 manager: SaTokenManager,
23}
24
25impl std::fmt::Debug for SaLogic {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.write_str("SaLogic { .. }")
28 }
29}
30
31impl SaLogic {
32 pub fn new(login_type: impl AsRef<str>, manager: SaTokenManager) -> Self {
35 Self {
36 login_type: Arc::from(login_type.as_ref()),
37 manager,
38 }
39 }
40
41 pub fn login_type(&self) -> &str {
43 &self.login_type
44 }
45
46 pub fn manager(&self) -> &SaTokenManager {
48 &self.manager
49 }
50
51 pub fn keys(&self) -> &SaKeys {
53 self.manager.keys()
54 }
55
56 pub async fn login(&self, login_id: impl Into<String>) -> SaTokenResult<TokenValue> {
58 self.manager
59 .login_with_options(
60 login_id,
61 Some(self.login_type.to_string()),
62 None,
63 None,
64 None,
65 None,
66 )
67 .await
68 }
69
70 pub async fn login_with_device(
72 &self,
73 login_id: impl Into<String>,
74 device: Option<String>,
75 extra: Option<serde_json::Value>,
76 ) -> SaTokenResult<TokenValue> {
77 self.manager
78 .login_with_options(
79 login_id,
80 Some(self.login_type.to_string()),
81 device,
82 extra,
83 None,
84 None,
85 )
86 .await
87 }
88
89 pub async fn logout(&self, token: &TokenValue) -> SaTokenResult<()> {
91 self.manager.logout(token).await
92 }
93
94 pub async fn logout_by_login_id(&self, login_id: &str) -> SaTokenResult<()> {
96 self.manager
97 .logout_by_login_id(&self.login_type, login_id)
98 .await
99 }
100
101 pub async fn kick_out(&self, login_id: &str) -> SaTokenResult<()> {
103 self.manager.kick_out(&self.login_type, login_id).await
104 }
105
106 pub async fn get_login_id(&self, token: &TokenValue) -> SaTokenResult<String> {
108 Ok(self
109 .manager
110 .get_token_info(token)
111 .await?
112 .login_id
113 .to_string())
114 }
115
116 pub async fn is_valid(&self, token: &TokenValue) -> bool {
118 self.manager.is_valid(token).await
119 }
120
121 pub async fn get_session(&self, login_id: &str) -> SaTokenResult<SaSession> {
123 self.manager
124 .get_session_with_type(&self.login_type, login_id)
125 .await
126 }
127
128 pub async fn save_session(&self, login_id: &str, session: &SaSession) -> SaTokenResult<()> {
130 self.manager
131 .save_session_with_type(&self.login_type, login_id, session)
132 .await
133 }
134
135 pub async fn delete_session(&self, login_id: &str) -> SaTokenResult<()> {
137 self.manager
138 .delete_session_with_type(&self.login_type, login_id)
139 .await
140 }
141
142 pub async fn get_terminal_list(
144 &self,
145 login_id: &str,
146 device_type: Option<&str>,
147 ) -> SaTokenResult<Vec<SaTerminalInfo>> {
148 self.manager
149 .get_terminal_list(&self.login_type, login_id, device_type)
150 .await
151 }
152
153 pub async fn get_terminal_info_by_token(
155 &self,
156 token: &TokenValue,
157 ) -> SaTokenResult<Option<SaTerminalInfo>> {
158 self.manager.get_terminal_info_by_token(token).await
159 }
160
161 pub async fn get_permissions(&self, login_id: &str) -> SaTokenResult<Vec<String>> {
165 self.manager
166 .get_permissions_with_type(&self.login_type, login_id)
167 .await
168 }
169
170 pub async fn set_permissions(&self, login_id: &str, perms: Vec<String>) -> SaTokenResult<()> {
172 self.manager
173 .set_permissions_with_type(&self.login_type, login_id, perms)
174 .await
175 }
176
177 pub async fn add_permission(
179 &self,
180 login_id: &str,
181 permission: impl Into<String>,
182 ) -> SaTokenResult<()> {
183 self.manager
184 .add_permission_with_type(&self.login_type, login_id, permission.into())
185 .await
186 }
187
188 pub async fn remove_permission(&self, login_id: &str, permission: &str) -> SaTokenResult<()> {
190 self.manager
191 .remove_permission_with_type(&self.login_type, login_id, permission)
192 .await
193 }
194
195 pub async fn clear_permissions(&self, login_id: &str) -> SaTokenResult<()> {
197 self.manager
198 .clear_permissions_with_type(&self.login_type, login_id)
199 .await
200 }
201
202 pub async fn has_permission(&self, login_id: &str, permission: &str) -> SaTokenResult<bool> {
204 self.manager
205 .authz_service()
206 .has_permission(&self.login_type, login_id, permission)
207 .await
208 }
209
210 pub async fn check_permission(&self, login_id: &str, permission: &str) -> SaTokenResult<()> {
212 self.manager
213 .authz_service()
214 .check_permission(&self.login_type, login_id, permission)
215 .await
216 }
217
218 pub async fn has_all_permissions(
220 &self,
221 login_id: &str,
222 permissions: &[&str],
223 ) -> SaTokenResult<bool> {
224 self.manager
225 .authz_service()
226 .has_all_permissions(&self.login_type, login_id, permissions)
227 .await
228 }
229
230 pub async fn has_any_permission(
232 &self,
233 login_id: &str,
234 permissions: &[&str],
235 ) -> SaTokenResult<bool> {
236 self.manager
237 .authz_service()
238 .has_any_permission(&self.login_type, login_id, permissions)
239 .await
240 }
241
242 pub async fn get_roles(&self, login_id: &str) -> SaTokenResult<Vec<String>> {
246 self.manager
247 .get_roles_with_type(&self.login_type, login_id)
248 .await
249 }
250
251 pub async fn set_roles(&self, login_id: &str, roles: Vec<String>) -> SaTokenResult<()> {
253 self.manager
254 .set_roles_with_type(&self.login_type, login_id, roles)
255 .await
256 }
257
258 pub async fn add_role(&self, login_id: &str, role: impl Into<String>) -> SaTokenResult<()> {
260 self.manager
261 .add_role_with_type(&self.login_type, login_id, role.into())
262 .await
263 }
264
265 pub async fn remove_role(&self, login_id: &str, role: &str) -> SaTokenResult<()> {
267 self.manager
268 .remove_role_with_type(&self.login_type, login_id, role)
269 .await
270 }
271
272 pub async fn clear_roles(&self, login_id: &str) -> SaTokenResult<()> {
274 self.manager
275 .clear_roles_with_type(&self.login_type, login_id)
276 .await
277 }
278
279 pub async fn has_role(&self, login_id: &str, role: &str) -> SaTokenResult<bool> {
281 self.manager
282 .authz_service()
283 .has_role(&self.login_type, login_id, role)
284 .await
285 }
286
287 pub async fn check_role(&self, login_id: &str, role: &str) -> SaTokenResult<()> {
289 self.manager
290 .authz_service()
291 .check_role(&self.login_type, login_id, role)
292 .await
293 }
294
295 pub async fn has_all_roles(&self, login_id: &str, roles: &[&str]) -> SaTokenResult<bool> {
297 self.manager
298 .authz_service()
299 .has_all_roles(&self.login_type, login_id, roles)
300 .await
301 }
302
303 pub async fn has_any_role(&self, login_id: &str, roles: &[&str]) -> SaTokenResult<bool> {
305 self.manager
306 .authz_service()
307 .has_any_role(&self.login_type, login_id, roles)
308 .await
309 }
310
311 pub async fn disable(&self, login_id: &str, time: i64) -> SaTokenResult<()> {
315 self.manager
316 .disable_with_type(&self.login_type, login_id, time)
317 .await
318 }
319
320 pub async fn disable_level(
322 &self,
323 login_id: &str,
324 service: &str,
325 level: i32,
326 time: i64,
327 ) -> SaTokenResult<()> {
328 self.manager
329 .disable_level_with_type(&self.login_type, login_id, service, level, time)
330 .await
331 }
332
333 pub async fn check_disable(&self, login_id: &str) -> SaTokenResult<()> {
335 self.manager
336 .check_disable_level_with_type(
337 &self.login_type,
338 login_id,
339 disable::DEFAULT_DISABLE_SERVICE,
340 disable::MIN_DISABLE_LEVEL,
341 )
342 .await
343 }
344
345 pub async fn get_disable_level(&self, login_id: &str, service: &str) -> SaTokenResult<i32> {
347 self.manager
348 .get_disable_level_with_type(&self.login_type, login_id, service)
349 .await
350 }
351
352 pub async fn untie_disable(&self, login_id: &str, service: &str) -> SaTokenResult<()> {
354 self.manager
355 .untie_disable_with_type(&self.login_type, login_id, service)
356 .await
357 }
358
359 pub async fn open_safe(
363 &self,
364 token: &TokenValue,
365 service: &str,
366 safe_time: i64,
367 ) -> SaTokenResult<()> {
368 self.manager.open_safe(token, service, safe_time).await
369 }
370
371 pub async fn check_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<()> {
373 self.manager.check_safe(token, service).await
374 }
375
376 pub async fn is_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<bool> {
378 self.manager.is_safe(token, service).await
379 }
380
381 pub async fn close_safe(&self, token: &TokenValue, service: &str) -> SaTokenResult<()> {
383 self.manager.close_safe(token, service).await
384 }
385
386 pub async fn get_token_session(&self, token: &TokenValue) -> SaTokenResult<SaSession> {
390 self.manager.get_token_session(token).await
391 }
392
393 pub async fn get_anon_token_session(&self, token: &TokenValue) -> SaTokenResult<SaSession> {
395 self.manager.get_anon_token_session(token).await
396 }
397
398 pub async fn save_token_session(
400 &self,
401 token: &TokenValue,
402 session: &SaSession,
403 ) -> SaTokenResult<()> {
404 self.manager.save_token_session(token, session).await
405 }
406
407 pub async fn delete_token_session(&self, token: &TokenValue) -> SaTokenResult<()> {
409 self.manager.delete_token_session(token).await
410 }
411
412 pub fn switch_to(&self, login_id: impl Into<String>) {
417 let target = login_id.into();
418 crate::context::SaTokenContext::with_current_mut(|inner| {
419 inner.switch_login_id = Some(target);
420 });
421 }
422
423 pub fn end_switch(&self) {
425 crate::context::SaTokenContext::with_current_mut(|inner| {
426 inner.switch_login_id = None;
427 });
428 }
429
430 pub fn is_switch(&self) -> bool {
432 crate::context::SaTokenContext::get_current()
433 .and_then(|c| c.switch_login_id())
434 .is_some()
435 }
436}
437
438#[cfg(test)]
439mod tests {
440 use super::*;
441 use sa_token_storage_memory::MemoryStorage;
442
443 fn make_manager() -> SaTokenManager {
444 SaTokenManager::new(
445 Arc::new(MemoryStorage::new()),
446 crate::SaTokenConfig::default(),
447 )
448 }
449
450 #[tokio::test]
451 async fn test_sa_logic_permission_isolation() {
452 let mgr = make_manager();
453 let admin = SaLogic::new("admin", mgr.clone());
454 let user = SaLogic::new("user", mgr);
455
456 admin
457 .set_permissions("10001", vec!["admin:read".to_string()])
458 .await
459 .unwrap();
460 user.set_permissions("10001", vec!["user:read".to_string()])
461 .await
462 .unwrap();
463
464 assert_eq!(
465 admin.get_permissions("10001").await.unwrap(),
466 vec!["admin:read".to_string()]
467 );
468 assert_eq!(
469 user.get_permissions("10001").await.unwrap(),
470 vec!["user:read".to_string()]
471 );
472 }
473
474 #[tokio::test]
475 async fn test_sa_logic_clone_is_independent_facade() {
476 let mgr = make_manager();
477 let a = SaLogic::new("shared", mgr.clone());
478 let b = SaLogic::new("shared", mgr);
479 assert_eq!(a.login_type(), b.login_type());
480 assert_eq!(a.login_type(), "shared");
481 }
482}