Skip to main content

sz_rust_orm_facade/data_scope/
evaluator.rs

1//! DataScopeEvaluator — 数据范围评估器
2//!
3//! 根据 DataScopeRule.mode 分发到对应 ModeEvaluator,
4//! 超级管理员绕过(记录审计日志),错误上报指标。
5
6use crate::data_scope::cache::DeptTreeCache;
7use crate::data_scope::context::DataScopeContext;
8use crate::data_scope::custom::CustomGeneratorRegistry;
9use crate::data_scope::error::DataScopeError;
10use crate::data_scope::metrics::DataScopeMetrics;
11use crate::data_scope::modes::all::AllMode;
12use crate::data_scope::modes::dept::DeptMode;
13use crate::data_scope::modes::self_mode::SelfMode;
14use crate::data_scope::modes::ModeEvaluator;
15use crate::data_scope::rule::{DataScopeMode, DataScopeRule};
16use crate::repository::WhereCondition;
17use async_trait::async_trait;
18use std::sync::Arc;
19use std::time::Instant;
20
21/// 数据范围评估器 trait
22#[async_trait]
23pub trait DataScopeEvaluator: Send + Sync {
24    /// 评估数据范围,返回 WHERE 条件列表
25    async fn evaluate(
26        &self,
27        ctx: &DataScopeContext,
28        rule: &DataScopeRule,
29    ) -> Result<Vec<WhereCondition>, DataScopeError>;
30}
31
32/// 默认评估器实现
33pub struct DefaultDataScopeEvaluator {
34    dept_cache: Arc<DeptTreeCache>,
35    custom_registry: Arc<CustomGeneratorRegistry>,
36    metrics: Arc<DataScopeMetrics>,
37}
38
39impl DefaultDataScopeEvaluator {
40    /// 创建评估器
41    pub fn new(
42        dept_cache: Arc<DeptTreeCache>,
43        custom_registry: Arc<CustomGeneratorRegistry>,
44        metrics: Arc<DataScopeMetrics>,
45    ) -> Self {
46        Self {
47            dept_cache,
48            custom_registry,
49            metrics,
50        }
51    }
52}
53
54#[async_trait]
55impl DataScopeEvaluator for DefaultDataScopeEvaluator {
56    async fn evaluate(
57        &self,
58        ctx: &DataScopeContext,
59        rule: &DataScopeRule,
60    ) -> Result<Vec<WhereCondition>, DataScopeError> {
61        let start = Instant::now();
62
63        if ctx.is_super {
64            self.metrics.record_bypass(ctx.user_id, &rule.target_table);
65            return Ok(Vec::new());
66        }
67
68        let result = match rule.mode {
69            DataScopeMode::All => AllMode.evaluate(ctx, rule).await,
70            DataScopeMode::Dept => DeptMode.evaluate(ctx, rule).await,
71            DataScopeMode::DeptAndSub => {
72                let mode = crate::data_scope::modes::dept_and_sub::DeptAndSubMode::new(
73                    self.dept_cache.clone(),
74                );
75                mode.evaluate(ctx, rule).await
76            }
77            DataScopeMode::Self_ => SelfMode.evaluate(ctx, rule).await,
78            DataScopeMode::Custom => {
79                let mode =
80                    crate::data_scope::modes::custom::CustomMode::new(self.custom_registry.clone());
81                mode.evaluate(ctx, rule).await
82            }
83        };
84
85        let elapsed_ms = start.elapsed().as_millis() as u64;
86        self.metrics.record_eval(elapsed_ms);
87
88        match result {
89            Ok(conditions) => {
90                self.metrics
91                    .record_hit(&rule.target_table, rule.mode.as_str());
92                Ok(conditions)
93            }
94            Err(ref e) => {
95                self.metrics
96                    .record_reject(e.error_code(), &rule.target_table);
97                Err(e.clone())
98            }
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106    use crate::data_scope::cache::{DeptTreeCache, DeptTreeProvider};
107
108    struct MockDeptProvider;
109
110    #[async_trait]
111    impl DeptTreeProvider for MockDeptProvider {
112        async fn sub_depts(&self, _dept_id: i64) -> Result<Vec<i64>, DataScopeError> {
113            Ok(vec![])
114        }
115    }
116
117    fn make_evaluator() -> DefaultDataScopeEvaluator {
118        DefaultDataScopeEvaluator::new(
119            Arc::new(DeptTreeCache::new(
120                Arc::new(MockDeptProvider),
121                std::time::Duration::from_secs(300),
122            )),
123            Arc::new(CustomGeneratorRegistry::new()),
124            Arc::new(DataScopeMetrics::new()),
125        )
126    }
127
128    #[tokio::test]
129    async fn test_evaluator_all_mode() {
130        let evaluator = make_evaluator();
131        let ctx = DataScopeContext::new(1, 5, false);
132        let rule = DataScopeRule::new("order", DataScopeMode::All);
133        let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
134        assert!(conditions.is_empty());
135    }
136
137    #[tokio::test]
138    async fn test_evaluator_dept_mode() {
139        let evaluator = make_evaluator();
140        let ctx = DataScopeContext::new(1, 5, false);
141        let rule = DataScopeRule::new("order", DataScopeMode::Dept).with_dept_field("dept_id");
142        let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
143        assert_eq!(conditions.len(), 1);
144    }
145
146    #[tokio::test]
147    async fn test_evaluator_self_mode() {
148        let evaluator = make_evaluator();
149        let ctx = DataScopeContext::new(10, 5, false);
150        let rule =
151            DataScopeRule::new("order", DataScopeMode::Self_).with_creator_field("creator_id");
152        let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
153        assert_eq!(conditions.len(), 1);
154    }
155
156    #[tokio::test]
157    async fn test_evaluator_super_bypass() {
158        let evaluator = make_evaluator();
159
160        let ctx = DataScopeContext::new(1, 5, true);
161        let rule = DataScopeRule::new("order", DataScopeMode::Dept).with_dept_field("dept_id");
162        let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
163        assert!(conditions.is_empty());
164    }
165
166    #[tokio::test]
167    async fn test_evaluator_error_propagation() {
168        let evaluator = make_evaluator();
169        let ctx = DataScopeContext::new(1, 5, false);
170        let rule = DataScopeRule::new("order", DataScopeMode::Dept);
171        let result = evaluator.evaluate(&ctx, &rule).await;
172        assert!(result.is_err());
173        assert_eq!(result.unwrap_err().error_code(), "DATA_SCOPE_INVALID_RULE");
174    }
175
176    #[tokio::test]
177    async fn test_evaluator_dept_and_sub_mode() {
178        let evaluator = make_evaluator();
179        let ctx = DataScopeContext::new(1, 5, false);
180        let rule =
181            DataScopeRule::new("order", DataScopeMode::DeptAndSub).with_dept_field("dept_id");
182        let conditions = evaluator.evaluate(&ctx, &rule).await.unwrap();
183        assert_eq!(conditions.len(), 1);
184    }
185}