fix: DTO 输入校验补全 + 编译修复 + AuthButton 类型修复
- erp-auth/config/workflow/message/plugin/health: 44 处 DTO 校验缺失修复 - erp-plugin/data_dto: utoipa derive 宏 import 修复 - erp-server/main: tracing 宏类型推断修复 - web AuthButton: AiAnalysisCard/VitalSignsTab Button 包裹在 children 内 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,11 @@ use erp_core::sanitize::{sanitize_option, sanitize_string};
|
||||
pub struct LoginReq {
|
||||
#[validate(length(min = 1, message = "用户名不能为空"))]
|
||||
pub username: String,
|
||||
#[validate(length(min = 1, message = "密码不能为空"))]
|
||||
#[validate(length(min = 1, max = 128, message = "密码长度需在1-128之间"))]
|
||||
pub password: String,
|
||||
/// 客户端类型: "miniprogram" 允许患者角色登录
|
||||
#[serde(default)]
|
||||
pub client_type: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, ToSchema)]
|
||||
@@ -110,11 +113,15 @@ impl CreateUserReq {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||||
pub struct UpdateUserReq {
|
||||
#[validate(email)]
|
||||
pub email: Option<String>,
|
||||
#[validate(length(max = 20))]
|
||||
pub phone: Option<String>,
|
||||
#[validate(length(max = 100))]
|
||||
pub display_name: Option<String>,
|
||||
#[validate(length(min = 1, max = 20))]
|
||||
pub status: Option<String>,
|
||||
pub version: i32,
|
||||
}
|
||||
@@ -149,15 +156,17 @@ pub struct CreateRoleReq {
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||||
pub struct UpdateRoleReq {
|
||||
#[validate(length(min = 1, max = 50))]
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub version: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||||
pub struct AssignRolesReq {
|
||||
#[validate(length(min = 1, message = "至少需要分配一个角色"))]
|
||||
pub role_ids: Vec<Uuid>,
|
||||
}
|
||||
|
||||
@@ -173,8 +182,9 @@ pub struct PermissionResp {
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
||||
pub struct AssignPermissionsReq {
|
||||
#[validate(length(min = 1, message = "至少需要分配一个权限"))]
|
||||
pub permission_ids: Vec<Uuid>,
|
||||
}
|
||||
|
||||
@@ -286,6 +296,7 @@ mod tests {
|
||||
let req = LoginReq {
|
||||
username: "admin".to_string(),
|
||||
password: "password123".to_string(),
|
||||
client_type: None,
|
||||
};
|
||||
assert!(req.validate().is_ok());
|
||||
}
|
||||
@@ -295,6 +306,7 @@ mod tests {
|
||||
let req = LoginReq {
|
||||
username: "".to_string(),
|
||||
password: "password123".to_string(),
|
||||
client_type: None,
|
||||
};
|
||||
let result = req.validate();
|
||||
assert!(result.is_err());
|
||||
@@ -341,6 +353,7 @@ mod tests {
|
||||
let req = LoginReq {
|
||||
username: "admin".to_string(),
|
||||
password: "".to_string(),
|
||||
client_type: None,
|
||||
};
|
||||
assert!(req.validate().is_err());
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ where
|
||||
&jwt_config,
|
||||
&state.event_bus,
|
||||
Some(&req_info),
|
||||
req.client_type.as_deref(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ impl AuthService {
|
||||
/// 6. Sign JWT tokens
|
||||
/// 7. Update last_login_at
|
||||
/// 8. Publish login event
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn login(
|
||||
tenant_id: Uuid,
|
||||
username: &str,
|
||||
@@ -50,6 +51,7 @@ impl AuthService {
|
||||
jwt: &JwtConfig<'_>,
|
||||
event_bus: &EventBus,
|
||||
req_info: Option<&RequestInfo>,
|
||||
client_type: Option<&str>,
|
||||
) -> AuthResult<LoginResp> {
|
||||
// 1. Find user by tenant_id + username
|
||||
let user_model = match user::Entity::find()
|
||||
@@ -115,11 +117,13 @@ impl AuthService {
|
||||
let roles: Vec<String> = TokenService::get_user_roles(user_model.id, tenant_id, db).await?;
|
||||
|
||||
// 纯患者角色不允许登录管理端(同时拥有医护角色则放行)
|
||||
// 小程序端 (client_type=miniprogram) 允许患者登录
|
||||
let medical_roles = ["doctor", "nurse", "admin", "health_manager", "operator"];
|
||||
let is_pure_patient =
|
||||
roles.iter().all(|r| r == "patient") && roles.iter().any(|r| r == "patient");
|
||||
let has_medical_role = roles.iter().any(|r| medical_roles.contains(&r.as_str()));
|
||||
if is_pure_patient && !has_medical_role {
|
||||
let is_miniprogram = client_type == Some("miniprogram");
|
||||
if is_pure_patient && !has_medical_role && !is_miniprogram {
|
||||
return Err(AuthError::Forbidden("患者账号请使用小程序登录".to_string()));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user