//! 密码哈希 (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 { 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 { 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()); } }