Skip to content
Clone
main
79 lines 2.5 KB Rust
//! 用户加载与状态判定 helper:service 层与 gRPC 层共用的唯一实现点。
//! gRPC 侧(`gaccount_helpers::store`)re-export 这些函数,避免 service 反向依赖传输层。
use crate::db::DbConn;
use crate::errors::{AuthError, AuthResult};
use crate::models::users::user_mfa::MfaStatus as ModelMfaStatus;
use crate::models::users::{user_mfa, users};
use chrono::Utc;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
pub const MAX_BATCH_USER_IDS: usize = 500;
pub async fn load_user(db: &DbConn, user_id: i64) -> AuthResult<users::Model> {
users::Entity::find_by_id(user_id)
.one(db.read())
.await?
.ok_or(AuthError::UserNotFound)
}
pub async fn load_active_user(db: &DbConn, user_id: i64) -> AuthResult<users::Model> {
let user = load_user(db, user_id).await?;
ensure_active(&user)?;
Ok(user)
}
pub fn is_active(user: &users::Model) -> bool {
user.deleted_at.is_none() && user.allow_use && !user.forbid_login
}
pub fn ensure_active(user: &users::Model) -> AuthResult<()> {
if user.deleted_at.is_some() || !user.allow_use {
return Err(AuthError::AccountUnavailable {
reason: "account is not available".to_owned(),
});
}
if user.forbid_login && {
match user.endtime_forbid_login_at {
Some(until) => until > Utc::now(),
None => true,
}
} {
return Err(AuthError::LoginForbidden {
reason: user.forbid_login_reason.clone(),
});
}
Ok(())
}
pub fn ensure_security_version(user: &users::Model, expected: i32) -> AuthResult<()> {
// `0` 是 proto 定义的「调用方无要求」;负数是没有意义的输入,按版本不符处理。
if expected < 0 {
return Err(AuthError::SecurityVersionStale {
current: user.security_version,
});
}
if expected > 0 && expected != user.security_version {
return Err(AuthError::SecurityVersionStale {
current: user.security_version,
});
}
Ok(())
}
pub async fn active_mfa_count(db: &DbConn, user_id: i64) -> AuthResult<u32> {
let factors = user_mfa::Entity::find()
.filter(user_mfa::Column::UserId.eq(user_id))
.all(db.read())
.await?;
Ok(factors
.iter()
.filter(|factor| {
factor.mfa_status == ModelMfaStatus::Enabled && factor.revoked_at.is_none()
})
.count() as u32)
}
pub async fn has_enabled_mfa(db: &DbConn, user_id: i64) -> AuthResult<bool> {
Ok(active_mfa_count(db, user_id).await? > 0)
}