sa-token-rust 0.1.15

A powerful Rust authentication and authorization framework
Documentation
# Distributed Session Management

## English

### Overview

The Distributed Session Management module enables session sharing across multiple microservices. It provides service authentication, cross-service session access, and attribute management with automatic timeout handling.

This module is designed for microservices architectures where multiple services need to share user authentication state and session data seamlessly.

### Architecture

```text
┌────────────────────────────────────────────────────────────────────┐
│                   Microservices Architecture                       │
│                   微服务架构                                        │
└────────────────────────────────────────────────────────────────────┘

    ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
    │  Service A   │  │  Service B   │  │  Service C   │
    │  (User API)  │  │  (Order API) │  │  (Pay API)   │
    └──────┬───────┘  └──────┬───────┘  └──────┬───────┘
           │                  │                  │
           └──────────────────┼──────────────────┘
                    ┌─────────▼──────────┐
                    │  Distributed       │
                    │  Session Storage   │
                    │  (Redis/Database)  │
                    └────────────────────┘

Each service can:
  - Create sessions for users
  - Access sessions created by other services
  - Share user authentication state
```

### Key Features

- **Cross-Service Session Sharing** - Share sessions across microservices
- **Service Authentication** - Verify service credentials with secret keys
- **Session Attributes** - Store custom key-value pairs for user context
- **Multi-Session Support** - One user can have multiple sessions (multi-device)
- **Automatic Cleanup** - TTL-based session expiration
- **Pluggable Storage** - Use custom storage backends (Redis, Database, Memory)
- **Permission-Based Access** - Fine-grained control via service permissions
- **Session Monitoring** - Track all active sessions per user

### Quick Start

```rust
use sa_token_core::{
    DistributedSessionManager, InMemoryDistributedStorage, ServiceCredential
};
use std::sync::Arc;
use std::time::Duration;
use chrono::Utc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create distributed session manager
    let storage = Arc::new(InMemoryDistributedStorage::new());
    let manager = DistributedSessionManager::new(
        storage,
        "service-main".to_string(),
        Duration::from_secs(3600), // 1 hour TTL
    );
    
    // Register a service
    let credential = ServiceCredential {
        service_id: "api-gateway".to_string(),
        service_name: "API Gateway".to_string(),
        secret_key: "secret123".to_string(),
        created_at: Utc::now(),
        permissions: vec!["read".to_string(), "write".to_string()],
    };
    manager.register_service(credential).await;
    
    // Verify service
    let verified = manager.verify_service("api-gateway", "secret123").await?;
    println!("Service verified: {}", verified.service_name);
    
    // Create session
    let session = manager.create_session(
        "user123".to_string(),
        "token456".to_string(),
    ).await?;
    
    // Set session attribute
    manager.set_attribute(
        &session.session_id,
        "role".to_string(),
        "admin".to_string(),
    ).await?;
    
    // Get session attribute
    if let Some(role) = manager.get_attribute(&session.session_id, "role").await? {
        println!("User role: {}", role);
    }
    
    // Get all sessions for user
    let sessions = manager.get_sessions_by_login_id("user123").await?;
    println!("User has {} active sessions", sessions.len());
    
    Ok(())
}
```

### Service Authentication Flow

```text
Service A                   Manager                    Service B
   |                           |                           |
   |-- register_service ------>|                           |
   |<----- registered ---------|                           |
   |                           |                           |
   |                           |<-- verify_service(id, secret)
   |                           |--- check credentials ---->|
   |                           |<----- verified ----------|
```

### Cross-Service Session Access

```text
Service A creates session:
  session_id: "uuid-123"
  login_id: "user123"
  attributes: {"role": "admin"}

Service B accesses session:
  get_session("uuid-123") -> Full session data
  Can read/modify attributes
  Updates last_access timestamp
```

### API Reference

#### DistributedSessionManager

**Methods:**
- `new(storage, service_id, timeout)` - Create manager
- `register_service(credential)` - Register a service
- `verify_service(id, secret)` - Verify service credentials
- `create_session(login_id, token)` - Create new session
- `get_session(session_id)` - Get session by ID
- `update_session(session)` - Update existing session
- `delete_session(session_id)` - Delete session
- `set_attribute(id, key, value)` - Set session attribute
- `get_attribute(id, key)` - Get session attribute
- `remove_attribute(id, key)` - Remove session attribute
- `get_sessions_by_login_id(login_id)` - Get all user sessions
- `delete_all_sessions(login_id)` - Delete all user sessions

---

## Use Cases

### 1. Single Sign-On (SSO) Across Services
Users log in once and access multiple services without re-authentication:

```text
User → Service A: Login
  ├─ Create session: session_id = "abc123"
  └─ Save to distributed storage

User → Service B: Request with session_id = "abc123"
  ├─ Service B retrieves session from storage
  ├─ Validates user is authenticated
  └─ Processes request ✅ (No re-login needed!)
```

### 2. Session Sharing for User Context
Services share user context and state:

```text
Service A stores: { "user_role": "admin", "department": "IT" }
Service B reads: Same session attributes available
Service C updates: { "last_order": "order_123" }
→ All services share the same session state!
```

### 3. Multi-Device Session Management
One user can have multiple active sessions:

```text
User: user_123
  ├─ Session 1: Web (Service A)
  ├─ Session 2: Mobile (Service B)
  └─ Session 3: Desktop (Service C)

All sessions can be:
  - Listed: get_sessions_by_login_id()
  - Managed individually
  - Terminated all at once: delete_all_sessions()
```

### 4. Microservices Architecture
Share user sessions across API Gateway, User Service, Order Service, etc.

### 5. Multi-Region Deployment
Synchronize sessions across different geographic regions using shared storage.

### 6. Load Balancing
Maintain session consistency across multiple server instances.

## Storage Backends

### Redis Implementation (Recommended)

```rust
use redis::AsyncCommands;

pub struct RedisDistributedStorage {
    client: redis::Client,
}

#[async_trait]
impl DistributedSessionStorage for RedisDistributedStorage {
    async fn save_session(&self, session: DistributedSession, ttl: Option<Duration>) 
        -> Result<(), SaTokenError> 
    {
        let mut conn = self.client.get_async_connection().await?;
        let key = format!("distributed:session:{}", session.session_id);
        let value = serde_json::to_string(&session)?;
        
        if let Some(ttl) = ttl {
            conn.set_ex(&key, value, ttl.as_secs() as usize).await?;
        } else {
            conn.set(&key, value).await?;
        }
        
        // Index by login_id for quick lookup
        let index_key = format!("distributed:login:{}", session.login_id);
        conn.sadd(index_key, &session.session_id).await?;
        
        Ok(())
    }
    
    // ... implement other methods
}
```

### Database Implementation

```rust
use sqlx::PgPool;

pub struct PostgresDistributedStorage {
    pool: PgPool,
}

#[async_trait]
impl DistributedSessionStorage for PostgresDistributedStorage {
    async fn save_session(&self, session: DistributedSession, ttl: Option<Duration>) 
        -> Result<(), SaTokenError> 
    {
        let expires_at = ttl.map(|t| Utc::now() + chrono::Duration::from_std(t).unwrap());
        
        sqlx::query!(
            "INSERT INTO distributed_sessions 
             (session_id, login_id, token, service_id, attributes, expires_at)
             VALUES ($1, $2, $3, $4, $5, $6)
             ON CONFLICT (session_id) DO UPDATE 
             SET attributes = $5, last_access = NOW()",
            session.session_id,
            session.login_id,
            session.token,
            session.service_id,
            serde_json::to_value(&session.attributes)?,
            expires_at,
        )
        .execute(&self.pool)
        .await?;
        
        Ok(())
    }
    
    // ... implement other methods
}
```

## Best Practices

### 1. Service Registration
Use crypto-secure secret generation for service credentials:

```rust
let credential = ServiceCredential {
    service_id: "user-service".to_string(),
    service_name: "User Management Service".to_string(),
    secret_key: generate_secure_secret(), // Use crypto-secure generation
    created_at: Utc::now(),
    permissions: vec!["user.read".to_string(), "user.write".to_string()],
};
manager.register_service(credential).await;
```

### 2. Session Creation with Context
Add relevant attributes immediately after session creation:

```rust
let session = manager.create_session(login_id, token).await?;

// Add relevant attributes immediately
manager.set_attribute(&session.session_id, "user_role".to_string(), "admin".to_string()).await?;
manager.set_attribute(&session.session_id, "department".to_string(), "IT".to_string()).await?;
manager.set_attribute(&session.session_id, "login_device".to_string(), "web".to_string()).await?;
```

### 3. Cross-Service Access Pattern
Always verify service identity and check permissions:

```rust
// 1. Verify service identity
let service_cred = manager.verify_service("service-b", request.secret).await?;

// 2. Check permissions
if !service_cred.permissions.contains(&"session.read".to_string()) {
    return Err(SaTokenError::PermissionDenied);
}

// 3. Access session
let session = manager.get_session(&request.session_id).await?;

// 4. Refresh to keep session alive
manager.refresh_session(&session.session_id).await?;
```

### 4. Multi-Device Logout
Support both individual and bulk logout:

```rust
// Logout from all devices
manager.delete_all_sessions(&login_id).await?;

// Or logout specific session
manager.delete_session(&session_id).await?;
```

### 5. Session Monitoring
Monitor user's active sessions for security:

```rust
let sessions = manager.get_sessions_by_login_id(&login_id).await?;

for session in sessions {
    println!("Session: {} from service: {}, last active: {}", 
        session.session_id,
        session.service_id,
        session.last_access
    );
    
    // Check for suspicious activity
    if is_suspicious(&session) {
        manager.delete_session(&session.session_id).await?;
    }
}
```

### 6. Security Considerations

- **Service Authentication**: Each service has unique secret_key
-**Permission-Based Access**: Services have explicit permissions
-**Session Timeout**: Configure appropriate TTL
-**Data Encryption**: Encrypt sensitive session attributes
-**Audit Logging**: Log session creation/deletion and cross-service access

### 7. Production Recommendations

1. **Use appropriate TTL** - Set session timeout based on security requirements (typically 1-24 hours)
2. **Use persistent storage** - Implement Redis/Database storage for production (not in-memory)
3. **Secure service credentials** - Use strong secret keys and rotate periodically
4. **Monitor session count** - Track active sessions per user to detect anomalies
5. **Implement cleanup** - Use storage TTL features for automatic cleanup
6. **Enable encryption** - Encrypt sensitive session attributes at rest

## Related Documentation

- [WebSocket Authentication]/guide/websocket-auth.md
- [Online User Management]/guide/online-user-management.md
- [Event Listener Guide]/guide/event-listener.md

## License

MIT OR Apache-2.0