pub struct NonceManager { /* private fields */ }Expand description
Nonce Manager | Nonce 管理器
Manages nonce generation and validation to prevent replay attacks 管理 nonce 的生成和验证以防止重放攻击
Implementations§
Source§impl NonceManager
impl NonceManager
Sourcepub fn new(storage: Arc<dyn SaStorage>, timeout: i64) -> Self
pub fn new(storage: Arc<dyn SaStorage>, timeout: i64) -> Self
Create new nonce manager | 创建新的 nonce 管理器
§Arguments | 参数
storage- Storage backend | 存储后端timeout- Nonce validity period in seconds | Nonce 有效期(秒)
Sourcepub fn generate(&self) -> String
pub fn generate(&self) -> String
Generate a new nonce | 生成新的 nonce
Generates a unique nonce using timestamp + UUID to ensure uniqueness. 使用时间戳 + UUID 生成唯一的 nonce 以确保唯一性。
§Returns | 返回
Unique nonce string in format: nonce_{timestamp_ms}_{uuid}
格式为 nonce_{时间戳_毫秒}_{uuid} 的唯一 nonce 字符串
§Format | 格式
nonce_1234567890123_abc123def456
│ │ │
│ │ └─ UUID (32 hex chars)
│ └─ Timestamp in milliseconds
└─ Prefix§Example | 示例
let nonce = nonce_manager.generate();
// Returns: "nonce_1701234567890_a1b2c3d4e5f6..."Sourcepub async fn store(&self, nonce: &str, login_id: &str) -> SaTokenResult<()>
pub async fn store(&self, nonce: &str, login_id: &str) -> SaTokenResult<()>
Store and mark nonce as used | 存储并标记 nonce 为已使用
Stores the nonce in storage with TTL, marking it as “consumed”. 将 nonce 以 TTL 存储在存储中,标记为“已消费“。
§Arguments | 参数
nonce- Nonce to store | 要存储的 noncelogin_id- Associated user ID | 关联的用户ID
§Storage Key | 存储键
sa:nonce:{nonce} → {"login_id": "...", "created_at": "..."}
§TTL Behavior | TTL 行为
The nonce is automatically removed after the timeout period. Nonce 会在超时期后自动移除。
§Example | 示例
nonce_manager.store("nonce_123_abc", "user_001").await?;
// Storage now contains: sa:nonce:nonce_123_abc (expires after timeout)Sourcepub async fn validate(&self, nonce: &str) -> SaTokenResult<bool>
pub async fn validate(&self, nonce: &str) -> SaTokenResult<bool>
Validate nonce and ensure it hasn’t been used | 验证 nonce 并确保未被使用
Checks if the nonce exists in storage. If it exists, it has been used. 检查 nonce 是否存在于存储中。如果存在,则已被使用。
§Arguments | 参数
nonce- Nonce to validate | 要验证的 nonce
§Returns | 返回
Ok(true)- Valid (not used yet) | 有效(尚未使用)Ok(false)- Invalid (already used) | 无效(已使用)
§Logic | 逻辑
Nonce NOT in storage → Valid (can be used)
Nonce IN storage → Invalid (already used)
Nonce 不在存储中 → 有效(可以使用)
Nonce 在存储中 → 无效(已使用)§Example | 示例
let is_valid = nonce_manager.validate("nonce_123").await?;
if is_valid {
// Proceed with operation
} else {
// Reject: nonce already used
}Sourcepub async fn validate_and_consume(
&self,
nonce: &str,
login_id: &str,
) -> SaTokenResult<()>
pub async fn validate_and_consume( &self, nonce: &str, login_id: &str, ) -> SaTokenResult<()>
Validate and consume nonce in one operation | 一次操作验证并消费 nonce
This is the primary method for using nonces in Sa-Token. It checks if the nonce is valid (not used) and immediately marks it as used. 这是在 Sa-Token 中使用 nonce 的主要方法。 它检查 nonce 是否有效(未使用)并立即将其标记为已使用。
§Arguments | 参数
nonce- Nonce to validate and consume | 要验证和消费的 noncelogin_id- Associated user ID | 关联的用户ID
§Returns | 返回
Ok(())- Nonce is valid and now consumed | Nonce 有效且已消费Err(NonceAlreadyUsed)- Nonce has already been used | Nonce 已被使用Err(StorageError)- Storage operation failed | 存储操作失败
§Security | 安全性
This operation is atomic from the application perspective: 此操作从应用程序角度来看是原子性的:
- Check if nonce exists (validate)
- If valid, store it immediately (consume)
- Return success
If two requests use the same nonce simultaneously, only one will succeed. 如果两个请求同时使用相同的 nonce,只有一个会成功。
§Integration with Login | 与登录集成
// Inside SaTokenManager::login_with_token_info()
if let Some(nonce) = &token_info.nonce {
self.nonce_manager
.validate_and_consume(nonce, &login_id)
.await?; // ← Prevents replay attacks
}§Example | 示例
// ✅ First use: Success
nonce_manager.validate_and_consume("nonce_123", "user_001").await?;
println!("Login successful");
// ❌ Second use: Error
let result = nonce_manager.validate_and_consume("nonce_123", "user_001").await;
assert!(matches!(result, Err(SaTokenError::NonceAlreadyUsed)));Sourcepub fn check_timestamp(
&self,
nonce: &str,
window_seconds: i64,
) -> SaTokenResult<bool>
pub fn check_timestamp( &self, nonce: &str, window_seconds: i64, ) -> SaTokenResult<bool>
Extract timestamp from nonce and check if it’s within valid time window 从 nonce 中提取时间戳并检查是否在有效时间窗口内
Provides additional security by validating the nonce timestamp. This prevents time-based attacks and ensures nonces are fresh. 通过验证 nonce 时间戳提供额外的安全性。 这可以防止基于时间的攻击并确保 nonce 是新鲜的。
§Arguments | 参数
nonce- Nonce to check | 要检查的 noncewindow_seconds- Maximum age of nonce in seconds | Nonce 的最大年龄(秒)
§Returns | 返回
Ok(true)- Timestamp is within the time window | 时间戳在时间窗口内Ok(false)- Timestamp is outside the time window (too old or future) | 时间戳在窗口外(太旧或未来)Err(InvalidNonceFormat)- Nonce format is invalid | Nonce 格式无效Err(InvalidNonceTimestamp)- Timestamp cannot be parsed | 时间戳无法解析
§Use Case | 使用场景
// Validate nonce and its timestamp
let nonce = request.get_nonce();
// Check timestamp: max 60 seconds old
if !nonce_manager.check_timestamp(&nonce, 60)? {
return Err("Nonce too old");
}
// Then validate and consume
nonce_manager.validate_and_consume(&nonce, user_id).await?;§Nonce Format | Nonce 格式
Expected format: nonce_{timestamp_ms}_{uuid}
期望格式:nonce_{时间戳_毫秒}_{uuid}
§Security Note | 安全说明
This check should be used in addition to validate_and_consume(),
not as a replacement. It provides defense-in-depth.
此检查应与 validate_and_consume() 一起使用,而不是替代。
它提供了深度防御。
Sourcepub async fn cleanup_expired(&self) -> SaTokenResult<()>
pub async fn cleanup_expired(&self) -> SaTokenResult<()>
Clean up expired nonces (implementation depends on storage) 清理过期的 nonce(实现依赖于存储)
§Note | 注意
Most storage backends (Redis, Memcached) automatically expire keys with TTL. This method is provided for storage backends that don’t support TTL. 大多数存储后端(Redis、Memcached)会自动过期带 TTL 的键。 此方法为不支持 TTL 的存储后端提供。
§Automatic Cleanup | 自动清理
- Redis: Uses EXPIRE command, automatic cleanup
- Memory: Built-in TTL support, automatic cleanup
- Database: May need manual cleanup (implement here)
§Manual Implementation | 手动实现
For databases without TTL support: 对于不支持 TTL 的数据库:
pub async fn cleanup_expired(&self) -> SaTokenResult<()> {
let cutoff = Utc::now() - Duration::seconds(self.timeout);
// DELETE FROM nonces WHERE created_at < cutoff
Ok(())
}Trait Implementations§
Source§impl Clone for NonceManager
impl Clone for NonceManager
Source§fn clone(&self) -> NonceManager
fn clone(&self) -> NonceManager
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more