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§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for NonceManager
impl !RefUnwindSafe for NonceManager
impl Send for NonceManager
impl Sync for NonceManager
impl Unpin for NonceManager
impl !UnwindSafe for NonceManager
Blanket Implementations§
§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§unsafe fn clone_to_uninit(&self, dest: *mut u8)
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)