fix(workflow): add tenant membership check to task delegation

The delegate method was accepting any UUID as delegate_to without
verifying the target user belongs to the same tenant. This allowed
cross-tenant task delegation. Added raw SQL check against users table
to avoid cross-module dependency on erp-auth.
This commit is contained in:
iven
2026-04-11 16:18:24 +08:00
parent c02fcecbfc
commit d8c3aba5d6

View File

@@ -2,8 +2,8 @@ use std::collections::HashMap;
use chrono::Utc; use chrono::Utc;
use sea_orm::{ use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set, ActiveModelTrait, ColumnTrait, ConnectionTrait, DatabaseBackend, EntityTrait,
TransactionTrait, PaginatorTrait, QueryFilter, Set, Statement, TransactionTrait,
}; };
use uuid::Uuid; use uuid::Uuid;
@@ -278,6 +278,25 @@ impl TaskService {
)); ));
} }
// 验证目标用户属于同一租户(使用 raw SQL 避免跨模块依赖 erp-auth
let result = db.query_one(Statement::from_sql_and_values(
DatabaseBackend::Postgres,
"SELECT EXISTS(SELECT 1 FROM users WHERE id = $1 AND tenant_id = $2 AND deleted_at IS NULL AND status = 'active') AS ok",
[req.delegate_to.into(), tenant_id.into()],
))
.await
.map_err(|e| WorkflowError::Validation(e.to_string()))?;
let target_ok = result
.and_then(|r| r.try_get::<bool>("", "ok").ok())
.unwrap_or(false);
if !target_ok {
return Err(WorkflowError::Validation(
"委派目标用户不存在或不属于当前租户".to_string(),
));
}
let mut active: task::ActiveModel = task_model.into(); let mut active: task::ActiveModel = task_model.into();
active.assignee_id = Set(Some(req.delegate_to)); active.assignee_id = Set(Some(req.delegate_to));
active.updated_at = Set(Utc::now()); active.updated_at = Set(Utc::now());