refactor(access_key): migrate auth to Argon2 password verification

- Replace custom hash check with Argon2 password verification
- Scan all un-revoked tokens for matching access key
- Add expiry validation per token with proper skip logic
This commit is contained in:
ZhenYi 2026-05-15 11:48:46 +08:00
parent 0703816482
commit b35d2d4fe7

View File

@ -1,5 +1,7 @@
use crate::AppService; use crate::AppService;
use crate::error::AppError; use crate::error::AppError;
use argon2::Argon2;
use argon2::password_hash::{PasswordHash, PasswordVerifier};
use chrono::Utc; use chrono::Utc;
use models::users::{user_activity_log, user_token}; use models::users::{user_activity_log, user_token};
use sea_orm::*; use sea_orm::*;
@ -191,22 +193,33 @@ impl AppService {
} }
pub async fn user_verify_access_key(&self, access_key: String) -> Result<Uuid, AppError> { pub async fn user_verify_access_key(&self, access_key: String) -> Result<Uuid, AppError> {
let access_key_hash = self.user_hash_access_key(&access_key); let access_key_models = user_token::Entity::find()
let access_key_model = user_token::Entity::find()
.filter(user_token::Column::TokenHash.eq(access_key_hash))
.filter(user_token::Column::IsRevoked.eq(false)) .filter(user_token::Column::IsRevoked.eq(false))
.one(&self.db) .all(&self.db)
.await? .await?;
.ok_or(AppError::Unauthorized)?;
if let Some(expires_at) = access_key_model.expires_at { for access_key_model in access_key_models {
if expires_at < Utc::now() { if access_key_model
return Err(AppError::Unauthorized); .expires_at
.map(|expires_at| expires_at < Utc::now())
.unwrap_or(false)
{
continue;
}
let Ok(hash) = PasswordHash::new(&access_key_model.token_hash) else {
continue;
};
if Argon2::default()
.verify_password(access_key.as_bytes(), &hash)
.is_ok()
{
return Ok(access_key_model.user);
} }
} }
Ok(access_key_model.user) Err(AppError::Unauthorized)
} }
fn user_generate_access_key(&self) -> String { fn user_generate_access_key(&self) -> String {