Files
hms/crates/erp-auth/src/error.rs
iven 6391a13467
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
fix(auth+miniprogram): 清除全部审计遗留问题
MEDIUM:
- WechatLoginReq/WechatBindPhoneReq 添加 Validate 派生 + 字段校验规则
- handler 中调用 req.validate() 并 map_err 转换
- 新增 AuthError::DbError 变体,wechat_service 所有 DB 错误从 Validation 改为 DbError
- DbError 映射到 AppError::Internal,不再误导前端

LOW:
- fetch_session 改用 reqwest Client.query() 构建参数,自动 URL 编码
- app.tsx PropsWithChildren<any> 改为 Record<string, unknown>
- login handleGetPhone 回调 e: any 改为内联类型
- appointment/create 4 个事件回调 e: any 改为内联类型
- health/input catch (e: any) 改为 catch (e: unknown) + instanceof 守卫
- report/detail Object.entries 去掉 [string, any] 类型断言
- wechat_service 移除 decrypt_phone_placeholder 函数,内联占位注释
2026-04-24 08:16:01 +08:00

103 lines
3.0 KiB
Rust

use erp_core::error::AppError;
/// Auth module error types
#[derive(Debug, thiserror::Error)]
pub enum AuthError {
#[error("用户名或密码错误")]
InvalidCredentials,
#[error("Token 已过期")]
TokenExpired,
#[error("Token 已被吊销")]
TokenRevoked,
#[error("用户已被{0}")]
UserDisabled(String),
#[error("密码哈希错误")]
HashError(String),
#[error("JWT 错误: {0}")]
JwtError(#[from] jsonwebtoken::errors::Error),
#[error("数据库错误: {0}")]
DbError(String),
#[error("{0}")]
Validation(String),
#[error("版本冲突: 数据已被其他操作修改,请刷新后重试")]
VersionMismatch,
}
impl From<AuthError> for AppError {
fn from(err: AuthError) -> Self {
match err {
AuthError::InvalidCredentials => AppError::Unauthorized,
AuthError::TokenExpired => AppError::Unauthorized,
AuthError::TokenRevoked => AppError::Unauthorized,
AuthError::UserDisabled(s) => AppError::Forbidden(s),
AuthError::Validation(s) => AppError::Validation(s),
AuthError::DbError(_) => AppError::Internal(err.to_string()),
AuthError::HashError(_) => AppError::Internal(err.to_string()),
AuthError::JwtError(_) => AppError::Unauthorized,
AuthError::VersionMismatch => AppError::VersionMismatch,
}
}
}
pub type AuthResult<T> = Result<T, AuthError>;
#[cfg(test)]
mod tests {
use super::*;
use erp_core::error::AppError;
#[test]
fn auth_error_invalid_credentials_maps_to_unauthorized() {
let app: AppError = AuthError::InvalidCredentials.into();
match app {
AppError::Unauthorized => {}
other => panic!("Expected Unauthorized, got {:?}", other),
}
}
#[test]
fn auth_error_token_expired_maps_to_unauthorized() {
let app: AppError = AuthError::TokenExpired.into();
match app {
AppError::Unauthorized => {}
other => panic!("Expected Unauthorized, got {:?}", other),
}
}
#[test]
fn auth_error_user_disabled_maps_to_forbidden() {
let app: AppError = AuthError::UserDisabled("已禁用".to_string()).into();
match app {
AppError::Forbidden(msg) => assert_eq!(msg, "已禁用"),
other => panic!("Expected Forbidden, got {:?}", other),
}
}
#[test]
fn auth_error_hash_error_maps_to_internal() {
let app: AppError = AuthError::HashError("argon2 failed".to_string()).into();
match app {
AppError::Internal(_) => {}
other => panic!("Expected Internal, got {:?}", other),
}
}
#[test]
fn auth_error_validation_maps_to_validation() {
let app: AppError = AuthError::Validation("用户名已存在".to_string()).into();
match app {
AppError::Validation(msg) => assert_eq!(msg, "用户名已存在"),
other => panic!("Expected Validation, got {:?}", other),
}
}
}