sa_token_core/distributed.rs
1//! Distributed Session Management Module | 分布式 Session 管理模块
2//!
3//! # Overview | 概述
4//!
5//! This module enables **distributed session management** for microservices architecture,
6//! allowing multiple services to share authentication sessions seamlessly.
7//! 本模块为微服务架构提供**分布式 Session 管理**,允许多个服务无缝共享认证会话。
8//!
9//! ## Architecture Context | 架构上下文
10//!
11//! ```text
12//! ┌────────────────────────────────────────────────────────────────────┐
13//! │ Microservices Architecture │
14//! │ 微服务架构 │
15//! └────────────────────────────────────────────────────────────────────┘
16//!
17//! ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
18//! │ Service A │ │ Service B │ │ Service C │
19//! │ (User API) │ │ (Order API) │ │ (Pay API) │
20//! └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
21//! │ │ │
22//! └──────────────────┼──────────────────┘
23//! │
24//! ┌─────────▼──────────┐
25//! │ Distributed │
26//! │ Session Storage │
27//! │ (Redis/Database) │
28//! └────────────────────┘
29//!
30//! Each service can:
31//! 每个服务可以:
32//! 1. Create sessions for users
33//! 为用户创建会话
34//! 2. Access sessions created by other services
35//! 访问其他服务创建的会话
36//! 3. Share user authentication state
37//! 共享用户认证状态
38//! ```
39//!
40//! ## Key Use Cases | 关键使用场景
41//!
42//! ### 1. Single Sign-On (SSO) Across Services | 跨服务单点登录
43//!
44//! ```text
45//! Scenario: User logs in to Service A and accesses Service B
46//! 场景:用户登录服务 A 并访问服务 B
47//!
48//! 1. User → Service A: Login
49//! 用户 → 服务 A:登录
50//! ├─ Service A creates session: session_id = "abc123"
51//! │ 服务 A 创建会话:session_id = "abc123"
52//! └─ Saves to distributed storage
53//! 保存到分布式存储
54//!
55//! 2. User → Service B: Request with session_id = "abc123"
56//! 用户 → 服务 B:请求带 session_id = "abc123"
57//! ├─ Service B retrieves session from storage
58//! │ 服务 B 从存储中获取会话
59//! ├─ Validates user is authenticated
60//! │ 验证用户已认证
61//! └─ Processes request ✅
62//! 处理请求 ✅
63//!
64//! No need to log in again! 无需再次登录!
65//! ```
66//!
67//! ### 2. Session Sharing for User Context | 会话共享用户上下文
68//!
69//! ```text
70//! Service A stores: { "user_role": "admin", "department": "IT" }
71//! 服务 A 存储:{ "user_role": "admin", "department": "IT" }
72//!
73//! Service B reads: Same session attributes available
74//! 服务 B 读取:相同的会话属性可用
75//!
76//! Service C updates: { "last_order": "order_123" }
77//! 服务 C 更新:{ "last_order": "order_123" }
78//!
79//! All services share the same session state!
80//! 所有服务共享相同的会话状态!
81//! ```
82//!
83//! ### 3. Multi-Device Session Management | 多设备会话管理
84//!
85//! ```text
86//! User: user_123
87//! ├─ Session 1: Web (Service A)
88//! │ 会话 1:网页(服务 A)
89//! ├─ Session 2: Mobile (Service B)
90//! │ 会话 2:移动端(服务 B)
91//! └─ Session 3: Desktop (Service C)
92//! 会话 3:桌面端(服务 C)
93//!
94//! All sessions can be:
95//! 所有会话可以:
96//! - Listed: get_sessions_by_login_id()
97//! - Managed individually
98//! - Terminated all at once: delete_all_sessions()
99//! ```
100//!
101//! ## Integration with Sa-Token | 与 Sa-Token 的集成
102//!
103//! ```text
104//! ┌─────────────────────────────────────────────────────────┐
105//! │ Sa-Token Core Flow │
106//! │ Sa-Token 核心流程 │
107//! └─────────────────────────────────────────────────────────┘
108//!
109//! SaTokenManager::login()
110//! ├─ 1. Generate token
111//! │ 生成 token
112//! ├─ 2. Create TokenInfo
113//! │ 创建 TokenInfo
114//! └─ 3. Create DistributedSession (if enabled)
115//! 创建 DistributedSession(如果启用)
116//! ├─ session_id: UUID
117//! ├─ login_id: user's login ID
118//! ├─ token: access token
119//! ├─ service_id: current service
120//! └─ attributes: custom data
121//!
122//! StpUtil::get_session()
123//! └─ Retrieves distributed session
124//! 获取分布式会话
125//!
126//! StpUtil::logout()
127//! └─ Deletes distributed session(s)
128//! 删除分布式会话
129//! ```
130
131//!
132//! ## Workflow Diagrams | 工作流程图
133//!
134//! ### Complete Session Lifecycle | 完整会话生命周期
135//!
136//! ```text
137//! ┌──────────────────────────────────────────────────────────────────┐
138//! │ Session Lifecycle │
139//! │ 会话生命周期 │
140//! └──────────────────────────────────────────────────────────────────┘
141//!
142//! User Service A Storage Service B
143//! 用户 服务 A 存储 服务 B
144//! │ │ │ │
145//! │ 1. Login │ │ │
146//! │ 登录 │ │ │
147//! ├────────────────────▶│ │ │
148//! │ │ 2. create_session() │
149//! │ │ 创建会话 │ │
150//! │ │ ├─ session_id: uuid │
151//! │ │ ├─ login_id: user_123 │
152//! │ │ ├─ token: access_token │
153//! │ │ └─ service_id: service-a │
154//! │ │ │ │
155//! │ │ 3. save_session()│ │
156//! │ │ 保存会话 │ │
157//! │ ├──────────────────▶│ │
158//! │ │ │ Store with TTL │
159//! │ │ │ 存储并设置 TTL │
160//! │ │ │ │
161//! │ 4. session_id │ │ │
162//! │ 返回会话 ID │ │ │
163//! │◀────────────────────│ │ │
164//! │ │ │ │
165//! │ 5. Request to Service B with session_id │
166//! │ 带 session_id 请求服务 B │
167//! ├────────────────────────────────────────────────────────────▶│
168//! │ │ │ │
169//! │ │ │ 6. get_session() │
170//! │ │ │ 获取会话 │
171//! │ │ │◀──────────────────│
172//! │ │ │ │
173//! │ │ │ 7. Return session│
174//! │ │ │ 返回会话数据 │
175//! │ │ ├──────────────────▶│
176//! │ │ │ │
177//! │ │ │ 8. refresh_session()
178//! │ │ │ 刷新会话 │
179//! │ │ │ (update last_access)
180//! │ │ │◀──────────────────│
181//! │ │ │ │
182//! │ 9. Response │ │ │
183//! │ 响应 │ │ │
184//! │◀────────────────────────────────────────────────────────────│
185//! │ │ │ │
186//! │ 10. Logout │ │ │
187//! │ 登出 │ │ │
188//! ├────────────────────▶│ │ │
189//! │ │ 11. delete_session() │
190//! │ │ 删除会话 │ │
191//! │ ├──────────────────▶│ │
192//! │ │ │ Remove from storage
193//! │ │ │ 从存储中移除 │
194//! │ │ │ │
195//! │ 12. Logout Success │ │ │
196//! │ 登出成功 │ │ │
197//! │◀────────────────────│ │ │
198//! │ │ │ │
199//! ```
200//!
201//! ### Service Authentication Flow | 服务认证流程
202//!
203//! ```text
204//! ┌──────────────────────────────────────────────────────────────────┐
205//! │ Service Inter-Communication │
206//! │ 服务间通信 │
207//! └──────────────────────────────────────────────────────────────────┘
208//!
209//! Service B Service A (Session Manager) Storage
210//! 服务 B 服务 A(会话管理器) 存储
211//! │ │ │
212//! │ 1. Register │ │
213//! │ 注册服务 │ │
214//! │ ├─ service_id │ │
215//! │ ├─ service_name │ │
216//! │ ├─ secret_key │ │
217//! │ └─ permissions │ │
218//! ├───────────────────────▶│ │
219//! │ │ Store credentials │
220//! │ │ 存储凭证 │
221//! │ │ (in memory) │
222//! │ │ │
223//! │ 2. Registered ✅ │ │
224//! │◀───────────────────────│ │
225//! │ │ │
226//! │ 3. Access session │ │
227//! │ 访问会话 │ │
228//! │ ├─ service_id │ │
229//! │ ├─ secret_key │ │
230//! │ └─ session_id │ │
231//! ├───────────────────────▶│ │
232//! │ │ 4. verify_service() │
233//! │ │ 验证服务 │
234//! │ │ ├─ Lookup service │
235//! │ │ └─ Compare secret_key │
236//! │ │ │
237//! │ │ 5. get_session() │
238//! │ │ 获取会话 │
239//! │ ├──────────────────────────────▶│
240//! │ │ │
241//! │ │ 6. Return session │
242//! │ │ 返回会话 │
243//! │ │◀──────────────────────────────│
244//! │ │ │
245//! │ 7. Session data ✅ │ │
246//! │◀───────────────────────│ │
247//! │ │ │
248//! ```
249//!
250//! ## Storage Backends | 存储后端
251//!
252//! The module is storage-agnostic. You can implement custom backends:
253//! 本模块与存储无关。您可以实现自定义后端:
254//!
255//! ### Redis Implementation (Recommended) | Redis 实现(推荐)
256//!
257//! ```rust,ignore
258//! use redis::AsyncCommands;
259//!
260//! pub struct RedisDistributedStorage {
261//! client: redis::Client,
262//! }
263//!
264//! #[async_trait]
265//! impl DistributedSessionStorage for RedisDistributedStorage {
266//! async fn save_session(&self, session: DistributedSession, ttl: Option<Duration>)
267//! -> Result<(), SaTokenError>
268//! {
269//! let mut conn = self.client.get_async_connection().await?;
270//! let key = format!("distributed:session:{}", session.session_id);
271//! let value = serde_json::to_string(&session)?;
272//!
273//! if let Some(ttl) = ttl {
274//! conn.set_ex(&key, value, ttl.as_secs() as usize).await?;
275//! } else {
276//! conn.set(&key, value).await?;
277//! }
278//!
279//! // Index by login_id
280//! let index_key = format!("distributed:login:{}", session.login_id);
281//! conn.sadd(index_key, &session.session_id).await?;
282//!
283//! Ok(())
284//! }
285//!
286//! // ... other methods
287//! }
288//! ```
289//!
290//! ### Database Implementation | 数据库实现
291//!
292//! ```rust,ignore
293//! use sqlx::PgPool;
294//!
295//! pub struct PostgresDistributedStorage {
296//! pool: PgPool,
297//! }
298//!
299//! #[async_trait]
300//! impl DistributedSessionStorage for PostgresDistributedStorage {
301//! async fn save_session(&self, session: DistributedSession, ttl: Option<Duration>)
302//! -> Result<(), SaTokenError>
303//! {
304//! let expires_at = ttl.map(|t| Utc::now() + chrono::Duration::from_std(t).unwrap());
305//!
306//! sqlx::query!(
307//! "INSERT INTO distributed_sessions
308//! (session_id, login_id, token, service_id, attributes, expires_at)
309//! VALUES ($1, $2, $3, $4, $5, $6)
310//! ON CONFLICT (session_id) DO UPDATE
311//! SET attributes = $5, last_access = NOW()",
312//! session.session_id,
313//! session.login_id,
314//! session.token,
315//! session.service_id,
316//! serde_json::to_value(&session.attributes)?,
317//! expires_at,
318//! )
319//! .execute(&self.pool)
320//! .await?;
321//!
322//! Ok(())
323//! }
324//!
325//! // ... other methods
326//! }
327//! ```
328//!
329//! ## Best Practices | 最佳实践
330//!
331//! ### 1. Service Registration | 服务注册
332//!
333//! ```rust,ignore
334//! // Initialize each service with unique credentials
335//! // 为每个服务初始化唯一凭证
336//! let credential = ServiceCredential {
337//! service_id: "user-service".to_string(),
338//! service_name: "User Management Service".to_string(),
339//! secret_key: generate_secure_secret(), // Use crypto-secure generation
340//! created_at: Utc::now(),
341//! permissions: vec!["user.read".to_string(), "user.write".to_string()],
342//! };
343//! manager.register_service(credential).await;
344//! ```
345//!
346//! ### 2. Session Creation with Context | 带上下文的会话创建
347//!
348//! ```rust,ignore
349//! // Create session with user context
350//! // 创建带用户上下文的会话
351//! let session = manager.create_session(login_id, token).await?;
352//!
353//! // Add relevant attributes immediately
354//! // 立即添加相关属性
355//! manager.set_attribute(&session.session_id, "user_role".to_string(), "admin".to_string()).await?;
356//! manager.set_attribute(&session.session_id, "department".to_string(), "IT".to_string()).await?;
357//! manager.set_attribute(&session.session_id, "login_device".to_string(), "web".to_string()).await?;
358//! ```
359//!
360//! ### 3. Cross-Service Access Pattern | 跨服务访问模式
361//!
362//! ```rust,ignore
363//! // Service B accesses session created by Service A
364//! // 服务 B 访问服务 A 创建的会话
365//!
366//! // 1. Verify service identity
367//! // 验证服务身份
368//! let service_cred = manager.verify_service("service-b", request.secret).await?;
369//!
370//! // 2. Check permissions
371//! // 检查权限
372//! if !service_cred.permissions.contains(&"session.read".to_string()) {
373//! return Err(SaTokenError::PermissionDenied);
374//! }
375//!
376//! // 3. Access session
377//! // 访问会话
378//! let session = manager.get_session(&request.session_id).await?;
379//!
380//! // 4. Refresh to keep session alive
381//! // 刷新以保持会话活跃
382//! manager.refresh_session(&session.session_id).await?;
383//! ```
384//!
385//! ### 4. Multi-Device Logout | 多设备登出
386//!
387//! ```rust,ignore
388//! // Logout from all devices
389//! // 从所有设备登出
390//! manager.delete_all_sessions(&login_id).await?;
391//!
392//! // Or logout specific session
393//! // 或登出特定会话
394//! manager.delete_session(&session_id).await?;
395//! ```
396//!
397//! ### 5. Session Monitoring | 会话监控
398//!
399//! ```rust,ignore
400//! // Monitor user's active sessions
401//! // 监控用户的活跃会话
402//! let sessions = manager.get_sessions_by_login_id(&login_id).await?;
403//!
404//! for session in sessions {
405//! println!("Session: {} from service: {}, last active: {}",
406//! session.session_id,
407//! session.service_id,
408//! session.last_access
409//! );
410//!
411//! // Check for suspicious activity
412//! // 检查可疑活动
413//! if is_suspicious(&session) {
414//! manager.delete_session(&session.session_id).await?;
415//! }
416//! }
417//! ```
418//!
419//! ## Security Considerations | 安全考虑
420//!
421//! ```text
422//! 1. ✅ Service Authentication | 服务认证
423//! - Each service has unique secret_key
424//! - Verify credentials before granting access
425//! - Rotate keys periodically
426//!
427//! 2. ✅ Permission-Based Access | 基于权限的访问
428//! - Services have explicit permissions
429//! - Check permissions before operations
430//! - Implement least-privilege principle
431//!
432//! 3. ✅ Session Timeout | 会话超时
433//! - Configure appropriate TTL
434//! - Auto-expire inactive sessions
435//! - Refresh on active use
436//!
437//! 4. ✅ Data Encryption | 数据加密
438//! - Encrypt sensitive session attributes
439//! - Use TLS for inter-service communication
440//! - Encrypt data at rest in storage
441//!
442//! 5. ✅ Audit Logging | 审计日志
443//! - Log session creation/deletion
444//! - Track cross-service access
445//! - Monitor for anomalies
446//! ```
447
448use crate::error::SaTokenError;
449use async_trait::async_trait;
450use serde::{Deserialize, Serialize};
451use std::collections::HashMap;
452use std::sync::Arc;
453use std::time::Duration;
454use chrono::{DateTime, Utc};
455use tokio::sync::RwLock;
456
457/// Distributed session data structure
458/// 分布式 Session 数据结构
459///
460/// Represents a session that can be shared across multiple services
461/// 表示可以在多个服务之间共享的 Session
462#[derive(Debug, Clone, Serialize, Deserialize)]
463pub struct DistributedSession {
464 /// Unique session identifier | 唯一 Session 标识符
465 pub session_id: String,
466
467 /// User login ID | 用户登录 ID
468 pub login_id: String,
469
470 /// Authentication token | 认证 Token
471 pub token: String,
472
473 /// ID of the service that created this session | 创建此 Session 的服务 ID
474 pub service_id: String,
475
476 /// Session creation time | Session 创建时间
477 pub create_time: DateTime<Utc>,
478
479 /// Last access time | 最后访问时间
480 pub last_access: DateTime<Utc>,
481
482 /// Session attributes (key-value pairs) | Session 属性(键值对)
483 pub attributes: HashMap<String, String>,
484}
485
486/// Service credential for inter-service authentication
487/// 服务间认证的服务凭证
488///
489/// Contains service identification and permission information
490/// 包含服务标识和权限信息
491#[derive(Debug, Clone, Serialize, Deserialize)]
492pub struct ServiceCredential {
493 /// Unique service identifier | 唯一服务标识符
494 pub service_id: String,
495
496 /// Human-readable service name | 可读的服务名称
497 pub service_name: String,
498
499 /// Service authentication secret key | 服务认证密钥
500 pub secret_key: String,
501
502 /// Service registration time | 服务注册时间
503 pub created_at: DateTime<Utc>,
504
505 /// List of permissions this service has | 该服务拥有的权限列表
506 pub permissions: Vec<String>,
507}
508
509/// Distributed session storage trait
510/// 分布式 Session 存储 trait
511///
512/// Implement this trait to provide custom storage backends
513/// 实现此 trait 以提供自定义存储后端
514#[async_trait]
515pub trait DistributedSessionStorage: Send + Sync {
516 /// Save a session to storage with optional TTL
517 /// 保存 Session 到存储,可选 TTL
518 ///
519 /// # Arguments | 参数
520 /// * `session` - Session to save | 要保存的 Session
521 /// * `ttl` - Time-to-live duration | 生存时间
522 async fn save_session(&self, session: DistributedSession, ttl: Option<Duration>) -> Result<(), SaTokenError>;
523
524 /// Get a session from storage
525 /// 从存储获取 Session
526 ///
527 /// # Arguments | 参数
528 /// * `session_id` - Session identifier | Session 标识符
529 async fn get_session(&self, session_id: &str) -> Result<Option<DistributedSession>, SaTokenError>;
530
531 /// Delete a session from storage
532 /// 从存储删除 Session
533 ///
534 /// # Arguments | 参数
535 /// * `session_id` - Session identifier | Session 标识符
536 async fn delete_session(&self, session_id: &str) -> Result<(), SaTokenError>;
537
538 /// Get all sessions for a specific user
539 /// 获取特定用户的所有 Sessions
540 ///
541 /// # Arguments | 参数
542 /// * `login_id` - User login ID | 用户登录 ID
543 async fn get_sessions_by_login_id(&self, login_id: &str) -> Result<Vec<DistributedSession>, SaTokenError>;
544}
545
546/// Distributed session manager
547/// 分布式 Session 管理器
548///
549/// Manages distributed sessions and service authentication
550/// 管理分布式 Sessions 和服务认证
551pub struct DistributedSessionManager {
552 /// Session storage backend | Session 存储后端
553 storage: Arc<dyn DistributedSessionStorage>,
554
555 /// Current service ID | 当前服务 ID
556 service_id: String,
557
558 /// Default session timeout | 默认 Session 超时时间
559 session_timeout: Duration,
560
561 /// Registered service credentials | 已注册的服务凭证
562 service_credentials: Arc<RwLock<HashMap<String, ServiceCredential>>>,
563}
564
565impl DistributedSessionManager {
566 /// Create a new distributed session manager
567 /// 创建新的分布式 Session 管理器
568 ///
569 /// # Arguments | 参数
570 /// * `storage` - Session storage implementation | Session 存储实现
571 /// * `service_id` - ID of this service | 此服务的 ID
572 /// * `session_timeout` - Default session timeout | 默认 Session 超时时间
573 ///
574 /// # Example | 示例
575 /// ```rust,ignore
576 /// let storage = Arc::new(MyDistributedStorage::new());
577 /// let manager = DistributedSessionManager::new(
578 /// storage,
579 /// "my-service".to_string(),
580 /// Duration::from_secs(3600),
581 /// );
582 /// ```
583 pub fn new(
584 storage: Arc<dyn DistributedSessionStorage>,
585 service_id: String,
586 session_timeout: Duration,
587 ) -> Self {
588 Self {
589 storage,
590 service_id,
591 session_timeout,
592 service_credentials: Arc::new(RwLock::new(HashMap::new())),
593 }
594 }
595
596 /// Register a service for inter-service authentication
597 /// 注册服务以进行服务间认证
598 ///
599 /// # Arguments | 参数
600 /// * `credential` - Service credential information | 服务凭证信息
601 ///
602 /// # Example | 示例
603 /// ```rust,ignore
604 /// let credential = ServiceCredential {
605 /// service_id: "api-gateway".to_string(),
606 /// service_name: "API Gateway".to_string(),
607 /// secret_key: "secret123".to_string(),
608 /// created_at: Utc::now(),
609 /// permissions: vec!["read".to_string(), "write".to_string()],
610 /// };
611 /// manager.register_service(credential).await;
612 /// ```
613 pub async fn register_service(&self, credential: ServiceCredential) {
614 let mut credentials = self.service_credentials.write().await;
615 credentials.insert(credential.service_id.clone(), credential);
616 }
617
618 /// Verify a service's credentials
619 /// 验证服务的凭证
620 ///
621 /// # Arguments | 参数
622 /// * `service_id` - Service identifier | 服务标识符
623 /// * `secret` - Service secret key | 服务密钥
624 ///
625 /// # Returns | 返回值
626 /// * `Ok(ServiceCredential)` - Service authenticated | 服务已认证
627 /// * `Err(PermissionDenied)` - Invalid credentials | 凭证无效
628 ///
629 /// # Example | 示例
630 /// ```rust,ignore
631 /// match manager.verify_service("api-gateway", "secret123").await {
632 /// Ok(cred) => println!("Service {} verified", cred.service_name),
633 /// Err(e) => println!("Verification failed: {}", e),
634 /// }
635 /// ```
636 pub async fn verify_service(&self, service_id: &str, secret: &str) -> Result<ServiceCredential, SaTokenError> {
637 let credentials = self.service_credentials.read().await;
638 if let Some(cred) = credentials.get(service_id) {
639 if cred.secret_key == secret {
640 return Ok(cred.clone());
641 }
642 }
643 Err(SaTokenError::PermissionDenied)
644 }
645
646 /// Create a new distributed session
647 /// 创建新的分布式 Session
648 ///
649 /// # Arguments | 参数
650 /// * `login_id` - User login ID | 用户登录 ID
651 /// * `token` - Authentication token | 认证 Token
652 ///
653 /// # Returns | 返回值
654 /// * `Ok(DistributedSession)` - Session created | Session 已创建
655 /// * `Err(SaTokenError)` - Creation failed | 创建失败
656 ///
657 /// # Example | 示例
658 /// ```rust,ignore
659 /// let session = manager.create_session(
660 /// "user123".to_string(),
661 /// "token456".to_string(),
662 /// ).await?;
663 /// println!("Session created: {}", session.session_id);
664 /// ```
665 pub async fn create_session(
666 &self,
667 login_id: String,
668 token: String,
669 ) -> Result<DistributedSession, SaTokenError> {
670 let session = DistributedSession {
671 session_id: uuid::Uuid::new_v4().to_string(),
672 login_id,
673 token,
674 service_id: self.service_id.clone(),
675 create_time: Utc::now(),
676 last_access: Utc::now(),
677 attributes: HashMap::new(),
678 };
679
680 self.storage.save_session(session.clone(), Some(self.session_timeout)).await?;
681 Ok(session)
682 }
683
684 /// Get a session by ID
685 /// 通过 ID 获取 Session
686 ///
687 /// # Arguments | 参数
688 /// * `session_id` - Session identifier | Session 标识符
689 ///
690 /// # Returns | 返回值
691 /// * `Ok(DistributedSession)` - Session found | 找到 Session
692 /// * `Err(SessionNotFound)` - Session not found | 未找到 Session
693 ///
694 /// # Example | 示例
695 /// ```rust,ignore
696 /// let session = manager.get_session("session-id-123").await?;
697 /// println!("User: {}", session.login_id);
698 /// ```
699 pub async fn get_session(&self, session_id: &str) -> Result<DistributedSession, SaTokenError> {
700 self.storage.get_session(session_id).await?
701 .ok_or(SaTokenError::SessionNotFound)
702 }
703
704 /// Update an existing session
705 /// 更新现有 Session
706 ///
707 /// # Arguments | 参数
708 /// * `session` - Updated session data | 更新后的 Session 数据
709 ///
710 /// # Example | 示例
711 /// ```rust,ignore
712 /// let mut session = manager.get_session("session-id").await?;
713 /// session.attributes.insert("role".to_string(), "admin".to_string());
714 /// manager.update_session(session).await?;
715 /// ```
716 pub async fn update_session(&self, session: DistributedSession) -> Result<(), SaTokenError> {
717 self.storage.save_session(session, Some(self.session_timeout)).await
718 }
719
720 /// Delete a session
721 /// 删除 Session
722 ///
723 /// # Arguments | 参数
724 /// * `session_id` - Session identifier | Session 标识符
725 ///
726 /// # Example | 示例
727 /// ```rust,ignore
728 /// manager.delete_session("session-id-123").await?;
729 /// ```
730 pub async fn delete_session(&self, session_id: &str) -> Result<(), SaTokenError> {
731 self.storage.delete_session(session_id).await
732 }
733
734 /// Refresh a session (update last access time)
735 /// 刷新 Session(更新最后访问时间)
736 ///
737 /// # Arguments | 参数
738 /// * `session_id` - Session identifier | Session 标识符
739 ///
740 /// # Example | 示例
741 /// ```rust,ignore
742 /// manager.refresh_session("session-id-123").await?;
743 /// ```
744 pub async fn refresh_session(&self, session_id: &str) -> Result<(), SaTokenError> {
745 let mut session = self.get_session(session_id).await?;
746 session.last_access = Utc::now();
747 self.update_session(session).await
748 }
749
750 /// Set a session attribute
751 /// 设置 Session 属性
752 ///
753 /// # Arguments | 参数
754 /// * `session_id` - Session identifier | Session 标识符
755 /// * `key` - Attribute key | 属性键
756 /// * `value` - Attribute value | 属性值
757 ///
758 /// # Example | 示例
759 /// ```rust,ignore
760 /// manager.set_attribute("session-id", "theme".to_string(), "dark".to_string()).await?;
761 /// ```
762 pub async fn set_attribute(
763 &self,
764 session_id: &str,
765 key: String,
766 value: String,
767 ) -> Result<(), SaTokenError> {
768 let mut session = self.get_session(session_id).await?;
769 session.attributes.insert(key, value);
770 session.last_access = Utc::now();
771 self.update_session(session).await
772 }
773
774 /// Get a session attribute
775 /// 获取 Session 属性
776 ///
777 /// # Arguments | 参数
778 /// * `session_id` - Session identifier | Session 标识符
779 /// * `key` - Attribute key | 属性键
780 ///
781 /// # Returns | 返回值
782 /// * `Some(value)` - Attribute found | 找到属性
783 /// * `None` - Attribute not found | 未找到属性
784 ///
785 /// # Example | 示例
786 /// ```rust,ignore
787 /// if let Some(theme) = manager.get_attribute("session-id", "theme").await? {
788 /// println!("Theme: {}", theme);
789 /// }
790 /// ```
791 pub async fn get_attribute(
792 &self,
793 session_id: &str,
794 key: &str,
795 ) -> Result<Option<String>, SaTokenError> {
796 let session = self.get_session(session_id).await?;
797 Ok(session.attributes.get(key).cloned())
798 }
799
800 /// Remove a session attribute
801 /// 移除 Session 属性
802 ///
803 /// # Arguments | 参数
804 /// * `session_id` - Session identifier | Session 标识符
805 /// * `key` - Attribute key | 属性键
806 ///
807 /// # Example | 示例
808 /// ```rust,ignore
809 /// manager.remove_attribute("session-id", "temp_data").await?;
810 /// ```
811 pub async fn remove_attribute(
812 &self,
813 session_id: &str,
814 key: &str,
815 ) -> Result<(), SaTokenError> {
816 let mut session = self.get_session(session_id).await?;
817 session.attributes.remove(key);
818 session.last_access = Utc::now();
819 self.update_session(session).await
820 }
821
822 /// Get all sessions for a specific user
823 /// 获取特定用户的所有 Sessions
824 ///
825 /// # Arguments | 参数
826 /// * `login_id` - User login ID | 用户登录 ID
827 ///
828 /// # Returns | 返回值
829 /// Vector of sessions | Sessions 向量
830 ///
831 /// # Example | 示例
832 /// ```rust,ignore
833 /// let sessions = manager.get_sessions_by_login_id("user123").await?;
834 /// println!("User has {} active sessions", sessions.len());
835 /// ```
836 pub async fn get_sessions_by_login_id(&self, login_id: &str) -> Result<Vec<DistributedSession>, SaTokenError> {
837 self.storage.get_sessions_by_login_id(login_id).await
838 }
839
840 /// Delete all sessions for a specific user
841 /// 删除特定用户的所有 Sessions
842 ///
843 /// # Arguments | 参数
844 /// * `login_id` - User login ID | 用户登录 ID
845 ///
846 /// # Example | 示例
847 /// ```rust,ignore
848 /// manager.delete_all_sessions("user123").await?;
849 /// ```
850 pub async fn delete_all_sessions(&self, login_id: &str) -> Result<(), SaTokenError> {
851 let sessions = self.get_sessions_by_login_id(login_id).await?;
852 for session in sessions {
853 self.delete_session(&session.session_id).await?;
854 }
855 Ok(())
856 }
857}
858
859/// In-memory distributed session storage implementation
860/// 内存分布式 Session 存储实现
861///
862/// For testing and development purposes
863/// 用于测试和开发目的
864pub struct InMemoryDistributedStorage {
865 /// Sessions storage: session_id -> DistributedSession
866 /// Sessions 存储: session_id -> DistributedSession
867 sessions: Arc<RwLock<HashMap<String, DistributedSession>>>,
868
869 /// Login index: login_id -> Vec<session_id>
870 /// 登录索引: login_id -> Vec<session_id>
871 login_index: Arc<RwLock<HashMap<String, Vec<String>>>>,
872}
873
874impl InMemoryDistributedStorage {
875 /// Create a new in-memory storage
876 /// 创建新的内存存储
877 pub fn new() -> Self {
878 Self {
879 sessions: Arc::new(RwLock::new(HashMap::new())),
880 login_index: Arc::new(RwLock::new(HashMap::new())),
881 }
882 }
883}
884
885impl Default for InMemoryDistributedStorage {
886 fn default() -> Self {
887 Self::new()
888 }
889}
890
891#[async_trait]
892impl DistributedSessionStorage for InMemoryDistributedStorage {
893 /// Save session to memory storage | 保存会话到内存存储
894 ///
895 /// # Implementation Details | 实现细节
896 ///
897 /// 1. Stores session in main HashMap by session_id
898 /// 在主 HashMap 中按 session_id 存储会话
899 /// 2. Updates login_index for quick user lookup
900 /// 更新 login_index 以快速查找用户
901 ///
902 /// # Note | 注意
903 ///
904 /// TTL is ignored in memory storage (for simplicity).
905 /// In production, use Redis or similar with built-in TTL support.
906 /// 内存存储中忽略 TTL(为简化实现)。
907 /// 在生产环境中,使用 Redis 或类似的内置 TTL 支持的存储。
908 async fn save_session(&self, session: DistributedSession, _ttl: Option<Duration>) -> Result<(), SaTokenError> {
909 let session_id = session.session_id.clone();
910 let login_id = session.login_id.clone();
911
912 // 1. Store session in main map
913 // 在主映射中存储会话
914 let mut sessions = self.sessions.write().await;
915 sessions.insert(session_id.clone(), session);
916
917 // 2. Update login index for this user
918 // 更新此用户的登录索引
919 let mut index = self.login_index.write().await;
920 let session_list = index.entry(login_id).or_insert_with(Vec::new);
921
922 // Add only if not already present (prevent duplicates)
923 // 仅在不存在时添加(防止重复)
924 if !session_list.contains(&session_id) {
925 session_list.push(session_id);
926 }
927
928 Ok(())
929 }
930
931 /// Get session from memory storage | 从内存存储获取会话
932 ///
933 /// # Returns | 返回
934 ///
935 /// * `Ok(Some(session))` - Session found | 找到会话
936 /// * `Ok(None)` - Session not found | 未找到会话
937 async fn get_session(&self, session_id: &str) -> Result<Option<DistributedSession>, SaTokenError> {
938 let sessions = self.sessions.read().await;
939 Ok(sessions.get(session_id).cloned())
940 }
941
942 /// Delete session from memory storage | 从内存存储删除会话
943 ///
944 /// # Implementation Details | 实现细节
945 ///
946 /// 1. Removes session from main HashMap
947 /// 从主 HashMap 中移除会话
948 /// 2. Removes session_id from login_index
949 /// 从 login_index 中移除 session_id
950 /// 3. Cleans up empty index entries
951 /// 清理空的索引条目
952 async fn delete_session(&self, session_id: &str) -> Result<(), SaTokenError> {
953 // 1. Remove from main storage and get session data
954 // 从主存储中移除并获取会话数据
955 let mut sessions = self.sessions.write().await;
956 if let Some(session) = sessions.remove(session_id) {
957 // 2. Update login index
958 // 更新登录索引
959 let mut index = self.login_index.write().await;
960 if let Some(session_ids) = index.get_mut(&session.login_id) {
961 // Remove this session_id from the list
962 // 从列表中移除此 session_id
963 session_ids.retain(|id| id != session_id);
964
965 // 3. Clean up: remove login_id entry if no sessions left
966 // 清理:如果没有剩余会话,移除 login_id 条目
967 if session_ids.is_empty() {
968 index.remove(&session.login_id);
969 }
970 }
971 }
972 Ok(())
973 }
974
975 /// Get all sessions for a user | 获取用户的所有会话
976 ///
977 /// # Implementation Details | 实现细节
978 ///
979 /// 1. Looks up session_ids in login_index
980 /// 在 login_index 中查找 session_ids
981 /// 2. Retrieves full session data for each session_id
982 /// 为每个 session_id 检索完整的会话数据
983 /// 3. Filters out any missing sessions (cleanup)
984 /// 过滤掉任何缺失的会话(清理)
985 ///
986 /// # Returns | 返回
987 ///
988 /// Vector of all active sessions for the user
989 /// 用户所有活跃会话的向量
990 async fn get_sessions_by_login_id(&self, login_id: &str) -> Result<Vec<DistributedSession>, SaTokenError> {
991 // 1. Get session IDs from index
992 // 从索引中获取会话 IDs
993 let index = self.login_index.read().await;
994 let session_ids = index.get(login_id).cloned().unwrap_or_default();
995
996 // 2. Retrieve full session data
997 // 检索完整的会话数据
998 let sessions = self.sessions.read().await;
999 let mut result = Vec::new();
1000
1001 for session_id in session_ids {
1002 if let Some(session) = sessions.get(&session_id) {
1003 result.push(session.clone());
1004 }
1005 // Note: If session not found, it was deleted but index not updated
1006 // This is a minor inconsistency acceptable in memory storage
1007 // 注意:如果未找到会话,说明会话已删除但索引未更新
1008 // 这是内存存储中可接受的小不一致
1009 }
1010
1011 Ok(result)
1012 }
1013}
1014
1015#[cfg(test)]
1016mod tests {
1017 use super::*;
1018
1019 #[tokio::test]
1020 async fn test_distributed_session_manager() {
1021 let storage = Arc::new(InMemoryDistributedStorage::new());
1022 let manager = DistributedSessionManager::new(
1023 storage,
1024 "service1".to_string(),
1025 Duration::from_secs(3600),
1026 );
1027
1028 let session = manager.create_session(
1029 "user1".to_string(),
1030 "token1".to_string(),
1031 ).await.unwrap();
1032
1033 let retrieved = manager.get_session(&session.session_id).await.unwrap();
1034 assert_eq!(retrieved.login_id, "user1");
1035 }
1036
1037 #[tokio::test]
1038 async fn test_session_attributes() {
1039 let storage = Arc::new(InMemoryDistributedStorage::new());
1040 let manager = DistributedSessionManager::new(
1041 storage,
1042 "service1".to_string(),
1043 Duration::from_secs(3600),
1044 );
1045
1046 let session = manager.create_session(
1047 "user2".to_string(),
1048 "token2".to_string(),
1049 ).await.unwrap();
1050
1051 manager.set_attribute(
1052 &session.session_id,
1053 "key1".to_string(),
1054 "value1".to_string(),
1055 ).await.unwrap();
1056
1057 let value = manager.get_attribute(&session.session_id, "key1").await.unwrap();
1058 assert_eq!(value, Some("value1".to_string()));
1059 }
1060
1061 #[tokio::test]
1062 async fn test_service_verification() {
1063 let storage = Arc::new(InMemoryDistributedStorage::new());
1064 let manager = DistributedSessionManager::new(
1065 storage,
1066 "service1".to_string(),
1067 Duration::from_secs(3600),
1068 );
1069
1070 let credential = ServiceCredential {
1071 service_id: "service2".to_string(),
1072 service_name: "Service 2".to_string(),
1073 secret_key: "secret123".to_string(),
1074 created_at: Utc::now(),
1075 permissions: vec!["read".to_string(), "write".to_string()],
1076 };
1077
1078 manager.register_service(credential.clone()).await;
1079
1080 let verified = manager.verify_service("service2", "secret123").await.unwrap();
1081 assert_eq!(verified.service_id, "service2");
1082
1083 let result = manager.verify_service("service2", "wrong_secret").await;
1084 assert!(result.is_err());
1085 }
1086
1087 #[tokio::test]
1088 async fn test_delete_all_sessions() {
1089 let storage = Arc::new(InMemoryDistributedStorage::new());
1090 let manager = DistributedSessionManager::new(
1091 storage,
1092 "service1".to_string(),
1093 Duration::from_secs(3600),
1094 );
1095
1096 manager.create_session("user3".to_string(), "token1".to_string()).await.unwrap();
1097 manager.create_session("user3".to_string(), "token2".to_string()).await.unwrap();
1098
1099 let sessions = manager.get_sessions_by_login_id("user3").await.unwrap();
1100 assert_eq!(sessions.len(), 2);
1101
1102 manager.delete_all_sessions("user3").await.unwrap();
1103
1104 let sessions = manager.get_sessions_by_login_id("user3").await.unwrap();
1105 assert_eq!(sessions.len(), 0);
1106 }
1107}