sa_token_core/distributed.rs
1//! Distributed Session Management Module | 分布式 Session 管理模块
2//!
3//! # Code Flow Logic | 代码流程逻辑
4//!
5//! ## English
6//!
7//! ### Overview
8//! This module provides distributed session management for microservices architecture.
9//! It enables session sharing across multiple services with service authentication,
10//! session attributes management, and automatic timeout handling.
11//!
12//! ### Service Registration Flow
13//! ```text
14//! 1. Create ServiceCredential
15//! ├─→ service_id: Unique service identifier
16//! ├─→ service_name: Human-readable name
17//! ├─→ secret_key: Service authentication secret
18//! ├─→ permissions: List of permissions
19//! └─→ created_at: Registration timestamp
20//! ↓
21//! 2. DistributedSessionManager.register_service(credential)
22//! └─→ Store in service_credentials HashMap
23//! ↓
24//! 3. Service Registered Successfully
25//! ```
26//!
27//! ### Service Authentication Flow
28//! ```text
29//! 1. Service Requests Access
30//! ├─→ Provide service_id
31//! └─→ Provide secret_key
32//! ↓
33//! 2. DistributedSessionManager.verify_service(service_id, secret)
34//! ├─→ Look up service in credentials map
35//! ├─→ Compare secret_key
36//! └─→ Return ServiceCredential if valid
37//! ↓
38//! 3. Authentication Result
39//! ├─→ Success: Return ServiceCredential
40//! └─→ Failure: Return PermissionDenied error
41//! ```
42//!
43//! ### Session Creation Flow
44//! ```text
45//! 1. User Logs In on Any Service
46//! ↓
47//! 2. create_session(login_id, token)
48//! ├─→ Generate unique session_id (UUID)
49//! ├─→ Record service_id (which service created it)
50//! ├─→ Set timestamps (create_time, last_access)
51//! └─→ Initialize empty attributes HashMap
52//! ↓
53//! 3. Save to Distributed Storage
54//! ├─→ storage.save_session(session, ttl)
55//! └─→ TTL: session_timeout duration
56//! ↓
57//! 4. Return DistributedSession
58//! ```
59//!
60//! ### Cross-Service Session Access Flow
61//! ```text
62//! 1. Service A Creates Session
63//! session_id: "uuid-123"
64//! service_id: "service-a"
65//! login_id: "user123"
66//! ↓
67//! 2. Service B Accesses Session
68//! get_session("uuid-123")
69//! ↓
70//! 3. Retrieve from Distributed Storage
71//! ├─→ storage.get_session(session_id)
72//! └─→ Returns full session data
73//! ↓
74//! 4. Service B Reads/Modifies Session
75//! ├─→ Access attributes
76//! ├─→ Update last_access time
77//! └─→ Save back to storage
78//! ```
79//!
80//! ### Session Attributes Flow
81//! ```text
82//! 1. set_attribute(session_id, key, value)
83//! ├─→ Get current session
84//! ├─→ session.attributes.insert(key, value)
85//! ├─→ Update last_access timestamp
86//! └─→ Save updated session
87//! ↓
88//! 2. get_attribute(session_id, key)
89//! ├─→ Get session from storage
90//! └─→ Return attributes.get(key)
91//! ↓
92//! 3. remove_attribute(session_id, key)
93//! ├─→ Get current session
94//! ├─→ session.attributes.remove(key)
95//! └─→ Save updated session
96//! ```
97//!
98//! ### Session Cleanup Flow
99//! ```text
100//! 1. delete_session(session_id)
101//! └─→ storage.delete_session(session_id)
102//! ↓
103//! 2. delete_all_sessions(login_id)
104//! ├─→ get_sessions_by_login_id(login_id)
105//! └─→ For each session: delete_session(id)
106//! ↓
107//! 3. Automatic Cleanup (TTL-based)
108//! └─→ Storage backend expires sessions after timeout
109//! ```
110//!
111//! ### Multi-Session Management
112//! ```text
113//! One user can have multiple sessions:
114//!
115//! user123:
116//! ├─→ Session 1 (created by service-a, web device)
117//! ├─→ Session 2 (created by service-b, mobile device)
118//! └─→ Session 3 (created by service-c, desktop app)
119//!
120//! All sessions share the same login_id but have unique session_ids
121//! Each service can access any session via distributed storage
122//! ```
123//!
124//! ## 中文
125//!
126//! ### 概述
127//! 本模块为微服务架构提供分布式 Session 管理。
128//! 它支持多个服务之间的 Session 共享,包括服务认证、Session 属性管理和自动超时处理。
129//!
130//! ### 服务注册流程
131//! ```text
132//! 1. 创建 ServiceCredential
133//! ├─→ service_id: 唯一服务标识符
134//! ├─→ service_name: 可读服务名称
135//! ├─→ secret_key: 服务认证密钥
136//! ├─→ permissions: 权限列表
137//! └─→ created_at: 注册时间戳
138//! ↓
139//! 2. DistributedSessionManager.register_service(credential)
140//! └─→ 存储到 service_credentials HashMap
141//! ↓
142//! 3. 服务注册成功
143//! ```
144//!
145//! ### 服务认证流程
146//! ```text
147//! 1. 服务请求访问
148//! ├─→ 提供 service_id
149//! └─→ 提供 secret_key
150//! ↓
151//! 2. DistributedSessionManager.verify_service(service_id, secret)
152//! ├─→ 在凭证映射中查找服务
153//! ├─→ 比较 secret_key
154//! └─→ 如果有效则返回 ServiceCredential
155//! ↓
156//! 3. 认证结果
157//! ├─→ 成功: 返回 ServiceCredential
158//! └─→ 失败: 返回 PermissionDenied 错误
159//! ```
160//!
161//! ### Session 创建流程
162//! ```text
163//! 1. 用户在任意服务上登录
164//! ↓
165//! 2. create_session(login_id, token)
166//! ├─→ 生成唯一 session_id (UUID)
167//! ├─→ 记录 service_id (创建它的服务)
168//! ├─→ 设置时间戳 (create_time, last_access)
169//! └─→ 初始化空的 attributes HashMap
170//! ↓
171//! 3. 保存到分布式存储
172//! ├─→ storage.save_session(session, ttl)
173//! └─→ TTL: session_timeout 持续时间
174//! ↓
175//! 4. 返回 DistributedSession
176//! ```
177//!
178//! ### 跨服务 Session 访问流程
179//! ```text
180//! 1. 服务 A 创建 Session
181//! session_id: "uuid-123"
182//! service_id: "service-a"
183//! login_id: "user123"
184//! ↓
185//! 2. 服务 B 访问 Session
186//! get_session("uuid-123")
187//! ↓
188//! 3. 从分布式存储获取
189//! ├─→ storage.get_session(session_id)
190//! └─→ 返回完整 session 数据
191//! ↓
192//! 4. 服务 B 读取/修改 Session
193//! ├─→ 访问属性
194//! ├─→ 更新 last_access 时间
195//! └─→ 保存回存储
196//! ```
197//!
198//! ### Session 属性流程
199//! ```text
200//! 1. set_attribute(session_id, key, value)
201//! ├─→ 获取当前 session
202//! ├─→ session.attributes.insert(key, value)
203//! ├─→ 更新 last_access 时间戳
204//! └─→ 保存更新后的 session
205//! ↓
206//! 2. get_attribute(session_id, key)
207//! ├─→ 从存储获取 session
208//! └─→ 返回 attributes.get(key)
209//! ↓
210//! 3. remove_attribute(session_id, key)
211//! ├─→ 获取当前 session
212//! ├─→ session.attributes.remove(key)
213//! └─→ 保存更新后的 session
214//! ```
215//!
216//! ### Session 清理流程
217//! ```text
218//! 1. delete_session(session_id)
219//! └─→ storage.delete_session(session_id)
220//! ↓
221//! 2. delete_all_sessions(login_id)
222//! ├─→ get_sessions_by_login_id(login_id)
223//! └─→ 对每个 session: delete_session(id)
224//! ↓
225//! 3. 自动清理 (基于 TTL)
226//! └─→ 存储后端在超时后自动过期 sessions
227//! ```
228//!
229//! ### 多 Session 管理
230//! ```text
231//! 一个用户可以有多个 sessions:
232//!
233//! user123:
234//! ├─→ Session 1 (service-a 创建, web 设备)
235//! ├─→ Session 2 (service-b 创建, 移动设备)
236//! └─→ Session 3 (service-c 创建, 桌面应用)
237//!
238//! 所有 sessions 共享相同的 login_id 但有唯一的 session_ids
239//! 每个服务都可以通过分布式存储访问任何 session
240//! ```
241
242use crate::error::SaTokenError;
243use async_trait::async_trait;
244use serde::{Deserialize, Serialize};
245use std::collections::HashMap;
246use std::sync::Arc;
247use std::time::Duration;
248use chrono::{DateTime, Utc};
249use tokio::sync::RwLock;
250
251/// Distributed session data structure
252/// 分布式 Session 数据结构
253///
254/// Represents a session that can be shared across multiple services
255/// 表示可以在多个服务之间共享的 Session
256#[derive(Debug, Clone, Serialize, Deserialize)]
257pub struct DistributedSession {
258 /// Unique session identifier | 唯一 Session 标识符
259 pub session_id: String,
260
261 /// User login ID | 用户登录 ID
262 pub login_id: String,
263
264 /// Authentication token | 认证 Token
265 pub token: String,
266
267 /// ID of the service that created this session | 创建此 Session 的服务 ID
268 pub service_id: String,
269
270 /// Session creation time | Session 创建时间
271 pub create_time: DateTime<Utc>,
272
273 /// Last access time | 最后访问时间
274 pub last_access: DateTime<Utc>,
275
276 /// Session attributes (key-value pairs) | Session 属性(键值对)
277 pub attributes: HashMap<String, String>,
278}
279
280/// Service credential for inter-service authentication
281/// 服务间认证的服务凭证
282///
283/// Contains service identification and permission information
284/// 包含服务标识和权限信息
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct ServiceCredential {
287 /// Unique service identifier | 唯一服务标识符
288 pub service_id: String,
289
290 /// Human-readable service name | 可读的服务名称
291 pub service_name: String,
292
293 /// Service authentication secret key | 服务认证密钥
294 pub secret_key: String,
295
296 /// Service registration time | 服务注册时间
297 pub created_at: DateTime<Utc>,
298
299 /// List of permissions this service has | 该服务拥有的权限列表
300 pub permissions: Vec<String>,
301}
302
303/// Distributed session storage trait
304/// 分布式 Session 存储 trait
305///
306/// Implement this trait to provide custom storage backends
307/// 实现此 trait 以提供自定义存储后端
308#[async_trait]
309pub trait DistributedSessionStorage: Send + Sync {
310 /// Save a session to storage with optional TTL
311 /// 保存 Session 到存储,可选 TTL
312 ///
313 /// # Arguments | 参数
314 /// * `session` - Session to save | 要保存的 Session
315 /// * `ttl` - Time-to-live duration | 生存时间
316 async fn save_session(&self, session: DistributedSession, ttl: Option<Duration>) -> Result<(), SaTokenError>;
317
318 /// Get a session from storage
319 /// 从存储获取 Session
320 ///
321 /// # Arguments | 参数
322 /// * `session_id` - Session identifier | Session 标识符
323 async fn get_session(&self, session_id: &str) -> Result<Option<DistributedSession>, SaTokenError>;
324
325 /// Delete a session from storage
326 /// 从存储删除 Session
327 ///
328 /// # Arguments | 参数
329 /// * `session_id` - Session identifier | Session 标识符
330 async fn delete_session(&self, session_id: &str) -> Result<(), SaTokenError>;
331
332 /// Get all sessions for a specific user
333 /// 获取特定用户的所有 Sessions
334 ///
335 /// # Arguments | 参数
336 /// * `login_id` - User login ID | 用户登录 ID
337 async fn get_sessions_by_login_id(&self, login_id: &str) -> Result<Vec<DistributedSession>, SaTokenError>;
338}
339
340/// Distributed session manager
341/// 分布式 Session 管理器
342///
343/// Manages distributed sessions and service authentication
344/// 管理分布式 Sessions 和服务认证
345pub struct DistributedSessionManager {
346 /// Session storage backend | Session 存储后端
347 storage: Arc<dyn DistributedSessionStorage>,
348
349 /// Current service ID | 当前服务 ID
350 service_id: String,
351
352 /// Default session timeout | 默认 Session 超时时间
353 session_timeout: Duration,
354
355 /// Registered service credentials | 已注册的服务凭证
356 service_credentials: Arc<RwLock<HashMap<String, ServiceCredential>>>,
357}
358
359impl DistributedSessionManager {
360 /// Create a new distributed session manager
361 /// 创建新的分布式 Session 管理器
362 ///
363 /// # Arguments | 参数
364 /// * `storage` - Session storage implementation | Session 存储实现
365 /// * `service_id` - ID of this service | 此服务的 ID
366 /// * `session_timeout` - Default session timeout | 默认 Session 超时时间
367 ///
368 /// # Example | 示例
369 /// ```rust,ignore
370 /// let storage = Arc::new(MyDistributedStorage::new());
371 /// let manager = DistributedSessionManager::new(
372 /// storage,
373 /// "my-service".to_string(),
374 /// Duration::from_secs(3600),
375 /// );
376 /// ```
377 pub fn new(
378 storage: Arc<dyn DistributedSessionStorage>,
379 service_id: String,
380 session_timeout: Duration,
381 ) -> Self {
382 Self {
383 storage,
384 service_id,
385 session_timeout,
386 service_credentials: Arc::new(RwLock::new(HashMap::new())),
387 }
388 }
389
390 /// Register a service for inter-service authentication
391 /// 注册服务以进行服务间认证
392 ///
393 /// # Arguments | 参数
394 /// * `credential` - Service credential information | 服务凭证信息
395 ///
396 /// # Example | 示例
397 /// ```rust,ignore
398 /// let credential = ServiceCredential {
399 /// service_id: "api-gateway".to_string(),
400 /// service_name: "API Gateway".to_string(),
401 /// secret_key: "secret123".to_string(),
402 /// created_at: Utc::now(),
403 /// permissions: vec!["read".to_string(), "write".to_string()],
404 /// };
405 /// manager.register_service(credential).await;
406 /// ```
407 pub async fn register_service(&self, credential: ServiceCredential) {
408 let mut credentials = self.service_credentials.write().await;
409 credentials.insert(credential.service_id.clone(), credential);
410 }
411
412 /// Verify a service's credentials
413 /// 验证服务的凭证
414 ///
415 /// # Arguments | 参数
416 /// * `service_id` - Service identifier | 服务标识符
417 /// * `secret` - Service secret key | 服务密钥
418 ///
419 /// # Returns | 返回值
420 /// * `Ok(ServiceCredential)` - Service authenticated | 服务已认证
421 /// * `Err(PermissionDenied)` - Invalid credentials | 凭证无效
422 ///
423 /// # Example | 示例
424 /// ```rust,ignore
425 /// match manager.verify_service("api-gateway", "secret123").await {
426 /// Ok(cred) => println!("Service {} verified", cred.service_name),
427 /// Err(e) => println!("Verification failed: {}", e),
428 /// }
429 /// ```
430 pub async fn verify_service(&self, service_id: &str, secret: &str) -> Result<ServiceCredential, SaTokenError> {
431 let credentials = self.service_credentials.read().await;
432 if let Some(cred) = credentials.get(service_id) {
433 if cred.secret_key == secret {
434 return Ok(cred.clone());
435 }
436 }
437 Err(SaTokenError::PermissionDenied)
438 }
439
440 /// Create a new distributed session
441 /// 创建新的分布式 Session
442 ///
443 /// # Arguments | 参数
444 /// * `login_id` - User login ID | 用户登录 ID
445 /// * `token` - Authentication token | 认证 Token
446 ///
447 /// # Returns | 返回值
448 /// * `Ok(DistributedSession)` - Session created | Session 已创建
449 /// * `Err(SaTokenError)` - Creation failed | 创建失败
450 ///
451 /// # Example | 示例
452 /// ```rust,ignore
453 /// let session = manager.create_session(
454 /// "user123".to_string(),
455 /// "token456".to_string(),
456 /// ).await?;
457 /// println!("Session created: {}", session.session_id);
458 /// ```
459 pub async fn create_session(
460 &self,
461 login_id: String,
462 token: String,
463 ) -> Result<DistributedSession, SaTokenError> {
464 let session = DistributedSession {
465 session_id: uuid::Uuid::new_v4().to_string(),
466 login_id,
467 token,
468 service_id: self.service_id.clone(),
469 create_time: Utc::now(),
470 last_access: Utc::now(),
471 attributes: HashMap::new(),
472 };
473
474 self.storage.save_session(session.clone(), Some(self.session_timeout)).await?;
475 Ok(session)
476 }
477
478 /// Get a session by ID
479 /// 通过 ID 获取 Session
480 ///
481 /// # Arguments | 参数
482 /// * `session_id` - Session identifier | Session 标识符
483 ///
484 /// # Returns | 返回值
485 /// * `Ok(DistributedSession)` - Session found | 找到 Session
486 /// * `Err(SessionNotFound)` - Session not found | 未找到 Session
487 ///
488 /// # Example | 示例
489 /// ```rust,ignore
490 /// let session = manager.get_session("session-id-123").await?;
491 /// println!("User: {}", session.login_id);
492 /// ```
493 pub async fn get_session(&self, session_id: &str) -> Result<DistributedSession, SaTokenError> {
494 self.storage.get_session(session_id).await?
495 .ok_or(SaTokenError::SessionNotFound)
496 }
497
498 /// Update an existing session
499 /// 更新现有 Session
500 ///
501 /// # Arguments | 参数
502 /// * `session` - Updated session data | 更新后的 Session 数据
503 ///
504 /// # Example | 示例
505 /// ```rust,ignore
506 /// let mut session = manager.get_session("session-id").await?;
507 /// session.attributes.insert("role".to_string(), "admin".to_string());
508 /// manager.update_session(session).await?;
509 /// ```
510 pub async fn update_session(&self, session: DistributedSession) -> Result<(), SaTokenError> {
511 self.storage.save_session(session, Some(self.session_timeout)).await
512 }
513
514 /// Delete a session
515 /// 删除 Session
516 ///
517 /// # Arguments | 参数
518 /// * `session_id` - Session identifier | Session 标识符
519 ///
520 /// # Example | 示例
521 /// ```rust,ignore
522 /// manager.delete_session("session-id-123").await?;
523 /// ```
524 pub async fn delete_session(&self, session_id: &str) -> Result<(), SaTokenError> {
525 self.storage.delete_session(session_id).await
526 }
527
528 /// Refresh a session (update last access time)
529 /// 刷新 Session(更新最后访问时间)
530 ///
531 /// # Arguments | 参数
532 /// * `session_id` - Session identifier | Session 标识符
533 ///
534 /// # Example | 示例
535 /// ```rust,ignore
536 /// manager.refresh_session("session-id-123").await?;
537 /// ```
538 pub async fn refresh_session(&self, session_id: &str) -> Result<(), SaTokenError> {
539 let mut session = self.get_session(session_id).await?;
540 session.last_access = Utc::now();
541 self.update_session(session).await
542 }
543
544 /// Set a session attribute
545 /// 设置 Session 属性
546 ///
547 /// # Arguments | 参数
548 /// * `session_id` - Session identifier | Session 标识符
549 /// * `key` - Attribute key | 属性键
550 /// * `value` - Attribute value | 属性值
551 ///
552 /// # Example | 示例
553 /// ```rust,ignore
554 /// manager.set_attribute("session-id", "theme".to_string(), "dark".to_string()).await?;
555 /// ```
556 pub async fn set_attribute(
557 &self,
558 session_id: &str,
559 key: String,
560 value: String,
561 ) -> Result<(), SaTokenError> {
562 let mut session = self.get_session(session_id).await?;
563 session.attributes.insert(key, value);
564 session.last_access = Utc::now();
565 self.update_session(session).await
566 }
567
568 /// Get a session attribute
569 /// 获取 Session 属性
570 ///
571 /// # Arguments | 参数
572 /// * `session_id` - Session identifier | Session 标识符
573 /// * `key` - Attribute key | 属性键
574 ///
575 /// # Returns | 返回值
576 /// * `Some(value)` - Attribute found | 找到属性
577 /// * `None` - Attribute not found | 未找到属性
578 ///
579 /// # Example | 示例
580 /// ```rust,ignore
581 /// if let Some(theme) = manager.get_attribute("session-id", "theme").await? {
582 /// println!("Theme: {}", theme);
583 /// }
584 /// ```
585 pub async fn get_attribute(
586 &self,
587 session_id: &str,
588 key: &str,
589 ) -> Result<Option<String>, SaTokenError> {
590 let session = self.get_session(session_id).await?;
591 Ok(session.attributes.get(key).cloned())
592 }
593
594 /// Remove a session attribute
595 /// 移除 Session 属性
596 ///
597 /// # Arguments | 参数
598 /// * `session_id` - Session identifier | Session 标识符
599 /// * `key` - Attribute key | 属性键
600 ///
601 /// # Example | 示例
602 /// ```rust,ignore
603 /// manager.remove_attribute("session-id", "temp_data").await?;
604 /// ```
605 pub async fn remove_attribute(
606 &self,
607 session_id: &str,
608 key: &str,
609 ) -> Result<(), SaTokenError> {
610 let mut session = self.get_session(session_id).await?;
611 session.attributes.remove(key);
612 session.last_access = Utc::now();
613 self.update_session(session).await
614 }
615
616 /// Get all sessions for a specific user
617 /// 获取特定用户的所有 Sessions
618 ///
619 /// # Arguments | 参数
620 /// * `login_id` - User login ID | 用户登录 ID
621 ///
622 /// # Returns | 返回值
623 /// Vector of sessions | Sessions 向量
624 ///
625 /// # Example | 示例
626 /// ```rust,ignore
627 /// let sessions = manager.get_sessions_by_login_id("user123").await?;
628 /// println!("User has {} active sessions", sessions.len());
629 /// ```
630 pub async fn get_sessions_by_login_id(&self, login_id: &str) -> Result<Vec<DistributedSession>, SaTokenError> {
631 self.storage.get_sessions_by_login_id(login_id).await
632 }
633
634 /// Delete all sessions for a specific user
635 /// 删除特定用户的所有 Sessions
636 ///
637 /// # Arguments | 参数
638 /// * `login_id` - User login ID | 用户登录 ID
639 ///
640 /// # Example | 示例
641 /// ```rust,ignore
642 /// manager.delete_all_sessions("user123").await?;
643 /// ```
644 pub async fn delete_all_sessions(&self, login_id: &str) -> Result<(), SaTokenError> {
645 let sessions = self.get_sessions_by_login_id(login_id).await?;
646 for session in sessions {
647 self.delete_session(&session.session_id).await?;
648 }
649 Ok(())
650 }
651}
652
653/// In-memory distributed session storage implementation
654/// 内存分布式 Session 存储实现
655///
656/// For testing and development purposes
657/// 用于测试和开发目的
658pub struct InMemoryDistributedStorage {
659 /// Sessions storage: session_id -> DistributedSession
660 /// Sessions 存储: session_id -> DistributedSession
661 sessions: Arc<RwLock<HashMap<String, DistributedSession>>>,
662
663 /// Login index: login_id -> Vec<session_id>
664 /// 登录索引: login_id -> Vec<session_id>
665 login_index: Arc<RwLock<HashMap<String, Vec<String>>>>,
666}
667
668impl InMemoryDistributedStorage {
669 /// Create a new in-memory storage
670 /// 创建新的内存存储
671 pub fn new() -> Self {
672 Self {
673 sessions: Arc::new(RwLock::new(HashMap::new())),
674 login_index: Arc::new(RwLock::new(HashMap::new())),
675 }
676 }
677}
678
679impl Default for InMemoryDistributedStorage {
680 fn default() -> Self {
681 Self::new()
682 }
683}
684
685#[async_trait]
686impl DistributedSessionStorage for InMemoryDistributedStorage {
687 async fn save_session(&self, session: DistributedSession, _ttl: Option<Duration>) -> Result<(), SaTokenError> {
688 let session_id = session.session_id.clone();
689 let login_id = session.login_id.clone();
690
691 let mut sessions = self.sessions.write().await;
692 sessions.insert(session_id.clone(), session);
693
694 let mut index = self.login_index.write().await;
695 index.entry(login_id)
696 .or_insert_with(Vec::new)
697 .push(session_id);
698
699 Ok(())
700 }
701
702 async fn get_session(&self, session_id: &str) -> Result<Option<DistributedSession>, SaTokenError> {
703 let sessions = self.sessions.read().await;
704 Ok(sessions.get(session_id).cloned())
705 }
706
707 async fn delete_session(&self, session_id: &str) -> Result<(), SaTokenError> {
708 let mut sessions = self.sessions.write().await;
709 if let Some(session) = sessions.remove(session_id) {
710 let mut index = self.login_index.write().await;
711 if let Some(session_ids) = index.get_mut(&session.login_id) {
712 session_ids.retain(|id| id != session_id);
713 if session_ids.is_empty() {
714 index.remove(&session.login_id);
715 }
716 }
717 }
718 Ok(())
719 }
720
721 async fn get_sessions_by_login_id(&self, login_id: &str) -> Result<Vec<DistributedSession>, SaTokenError> {
722 let index = self.login_index.read().await;
723 let session_ids = index.get(login_id).cloned().unwrap_or_default();
724
725 let sessions = self.sessions.read().await;
726 let mut result = Vec::new();
727 for session_id in session_ids {
728 if let Some(session) = sessions.get(&session_id) {
729 result.push(session.clone());
730 }
731 }
732
733 Ok(result)
734 }
735}
736
737#[cfg(test)]
738mod tests {
739 use super::*;
740
741 #[tokio::test]
742 async fn test_distributed_session_manager() {
743 let storage = Arc::new(InMemoryDistributedStorage::new());
744 let manager = DistributedSessionManager::new(
745 storage,
746 "service1".to_string(),
747 Duration::from_secs(3600),
748 );
749
750 let session = manager.create_session(
751 "user1".to_string(),
752 "token1".to_string(),
753 ).await.unwrap();
754
755 let retrieved = manager.get_session(&session.session_id).await.unwrap();
756 assert_eq!(retrieved.login_id, "user1");
757 }
758
759 #[tokio::test]
760 async fn test_session_attributes() {
761 let storage = Arc::new(InMemoryDistributedStorage::new());
762 let manager = DistributedSessionManager::new(
763 storage,
764 "service1".to_string(),
765 Duration::from_secs(3600),
766 );
767
768 let session = manager.create_session(
769 "user2".to_string(),
770 "token2".to_string(),
771 ).await.unwrap();
772
773 manager.set_attribute(
774 &session.session_id,
775 "key1".to_string(),
776 "value1".to_string(),
777 ).await.unwrap();
778
779 let value = manager.get_attribute(&session.session_id, "key1").await.unwrap();
780 assert_eq!(value, Some("value1".to_string()));
781 }
782
783 #[tokio::test]
784 async fn test_service_verification() {
785 let storage = Arc::new(InMemoryDistributedStorage::new());
786 let manager = DistributedSessionManager::new(
787 storage,
788 "service1".to_string(),
789 Duration::from_secs(3600),
790 );
791
792 let credential = ServiceCredential {
793 service_id: "service2".to_string(),
794 service_name: "Service 2".to_string(),
795 secret_key: "secret123".to_string(),
796 created_at: Utc::now(),
797 permissions: vec!["read".to_string(), "write".to_string()],
798 };
799
800 manager.register_service(credential.clone()).await;
801
802 let verified = manager.verify_service("service2", "secret123").await.unwrap();
803 assert_eq!(verified.service_id, "service2");
804
805 let result = manager.verify_service("service2", "wrong_secret").await;
806 assert!(result.is_err());
807 }
808
809 #[tokio::test]
810 async fn test_delete_all_sessions() {
811 let storage = Arc::new(InMemoryDistributedStorage::new());
812 let manager = DistributedSessionManager::new(
813 storage,
814 "service1".to_string(),
815 Duration::from_secs(3600),
816 );
817
818 manager.create_session("user3".to_string(), "token1".to_string()).await.unwrap();
819 manager.create_session("user3".to_string(), "token2".to_string()).await.unwrap();
820
821 let sessions = manager.get_sessions_by_login_id("user3").await.unwrap();
822 assert_eq!(sessions.len(), 2);
823
824 manager.delete_all_sessions("user3").await.unwrap();
825
826 let sessions = manager.get_sessions_by_login_id("user3").await.unwrap();
827 assert_eq!(sessions.len(), 0);
828 }
829}