feat(saas): Phase 1 — 基础框架与账号管理模块
- 新增 zclaw-saas crate 作为 workspace 成员 - 配置系统 (TOML + 环境变量覆盖) - 错误类型体系 (SaasError 16 变体, IntoResponse) - SQLite 数据库 (12 表 schema, 内存/文件双模式, 3 系统角色种子数据) - JWT 认证 (签发/验证/刷新) - Argon2id 密码哈希 - 认证中间件 (公开/受保护路由分层) - 账号管理 CRUD + API Token 管理 + 操作日志 - 7 单元测试 + 5 集成测试全部通过
This commit is contained in:
48
crates/zclaw-saas/src/auth/password.rs
Normal file
48
crates/zclaw-saas/src/auth/password.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
//! 密码哈希 (Argon2id)
|
||||
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
||||
Argon2,
|
||||
};
|
||||
|
||||
use crate::error::{SaasError, SaasResult};
|
||||
|
||||
/// 哈希密码
|
||||
pub fn hash_password(password: &str) -> SaasResult<String> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let argon2 = Argon2::default();
|
||||
let hash = argon2
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.map_err(|e| SaasError::PasswordHash(e.to_string()))?;
|
||||
Ok(hash.to_string())
|
||||
}
|
||||
|
||||
/// 验证密码
|
||||
pub fn verify_password(password: &str, hash: &str) -> SaasResult<bool> {
|
||||
let parsed_hash = PasswordHash::new(hash)
|
||||
.map_err(|e| SaasError::PasswordHash(e.to_string()))?;
|
||||
Ok(Argon2::default()
|
||||
.verify_password(password.as_bytes(), &parsed_hash)
|
||||
.is_ok())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_hash_and_verify() {
|
||||
let hash = hash_password("correct_password").unwrap();
|
||||
assert!(verify_password("correct_password", &hash).unwrap());
|
||||
assert!(!verify_password("wrong_password", &hash).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_different_hashes_for_same_password() {
|
||||
let hash1 = hash_password("same_password").unwrap();
|
||||
let hash2 = hash_password("same_password").unwrap();
|
||||
assert_ne!(hash1, hash2);
|
||||
assert!(verify_password("same_password", &hash1).unwrap());
|
||||
assert!(verify_password("same_password", &hash2).unwrap());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user