来源：https://basicapp.docs.xihanfun.com/backend/approval

# 审批与约束规则

菜单目录 `/approval` 下有两个页面，它们解决的是不同的问题，容易混淆：

| 页面 | 归属 | 解决什么 |
| --- | --- | --- |
| **审批中心** `/approval/center` | 工作流模块 | **单据审批**：业务数据要人来批，一步或多级 |
| **约束规则** `/approval/constraint` | Saas（`SysConstraintRule` + `SysConstraintRuleItem`） | **RBAC 约束引擎**：授权本身合不合规 |

## 审批中心

审批统一走 [工作流](./workflow)：业务单据按「业务编码 = 流程编码、单据主键 = 实例业务相关性标识」挂到流程上，审批人按角色、部门、岗位、发起人主管等规则解析，在审批中心的「待我审批」里办理，流程结束时回调业务回写单据。

一步审批就是只有一个人工任务节点的流程；多级、会签、条件分支、超时自动处理、并行汇合都在同一套机制里，改流程只需在设计器里发新版本。业务怎么接入见 [工作流 · 审批业务接入](./workflow#审批业务接入)。

::: tip 5.8.0 起不再有「系统审查」
早先 Saas 自带的通用审批单 `SysReview` / `SysReviewLog` 已撤掉，权限申请改由工作流审批。升级脚本删除两张旧表；存量的待审批权限申请没有对应流程，统一置为已撤回，申请人重新提交即走新流程。
:::

## 约束规则引擎

这套东西管的**不是业务数据，而是权限本身**：判断一次授权是否违反组织的合规规则。

::: warning 当前只执行静态职责分离（SSD）
规则可以按下面八类维护，但真正有代码评估的只有 **SSD**（目标为角色的规则），在三条授权写入路径上执行：分配角色（含角色成员批量调整、让绑定重新生效的改状态 / 改有效期）、调整角色继承、审批通过带角色的权限申请。其余类型目前只是可维护的规则数据，不会拦截任何操作；规则也不参与请求期鉴权。
:::

`SysConstraintRule` 的结构：

| 字段 | 说明 | 默认 |
| --- | --- | --- |
| `RuleCode` / `RuleName` | 规则编码与名称 | — |
| `ConstraintType` | **约束类型**（见下表） | `SSD` |
| `TargetType` | 约束对象类型（角色 / 权限 / …） | `Role` |
| `Parameters` | 规则参数（JSON）；SSD 读 `maxAllowed`：同组内最多同时持有几个目标，缺省 1 | — |
| **`ViolationAction`** | **违规时怎么处理**（见下表） | `Deny` |
| `Priority` | 优先级 | `0` |
| `EffectiveTime` / `ExpirationTime` | 生效时间窗 | — |
| `Status` | 启停 | `Enabled` |

`SysConstraintRuleItem` 是规则的目标项集合（如「这三个角色互斥」里的那三个角色）。

### 八类约束

| 类型 | 值 | 含义 | 典型场景 | 当前是否执行 |
| --- | --- | --- | --- | --- |
| **SSD** 静态职责分离 | 0 | 一个用户**不能同时被授予**这组角色 | 「制单员」与「审核员」不能是同一人 | 执行（见上） |
| **DSD** 动态职责分离 | 1 | 可以都有，但**同一会话内不能同时激活** | 平时可切换身份，单次操作只能用一个 | 不执行：会话角色激活尚无写入口 |
| **互斥约束** | 2 | 指定对象互相排斥 | 两个权限不能共存 | 不执行 |
| **基数约束** | 3 | 数量上限 | 「超级管理员最多 3 人」 | 不执行；限制角色人数请用角色的成员上限 `MaxMembers` |
| **先决条件** | 4 | 授予 A 前必须先有 B | 给「财务审批」前必须先有「财务查看」 | 不执行 |
| **时间约束** | 5 | 只在特定时间窗内有效 | 临时权限只在项目期内 | 不执行；授权绑定自带生效 / 失效时间 |
| **位置约束** | 6 | 按 IP 限制 | 财务操作只能在办公网 | 不执行 |
| **自定义** | 99 | 扩展点 | — | 不执行 |

SSD 评估时展开角色继承链：规则指向角色 A，任何继承了 A 的角色都视为持有 A；停用的角色同样计入（随时可能重新启用）。

### 四种违规处理

| 动作 | 值 | 当前效果 |
| --- | --- | --- |
| `Deny` 拒绝 | 0 | 直接阻断，整次授权写入失败，错误信息带规则编码、名称与冲突角色主键 |
| `Warning` 警告 | 1 | 放行，写一条 Warning 级应用日志；不会提示操作人 |
| `Log` 记录日志 | 2 | 放行，同样写一条 Warning 级应用日志 |
| `RequireApproval` 需审批 | 3 | **与 `Deny` 相同，直接阻断**；不会生成审批单，也不会转入审批流程 |

::: tip 上线新规则的姿势
直接上 `Deny` 风险很大——存量数据里往往已经有一批违规状态，一开就挡住相关人员之后的角色调整。

推荐路径：先用 `Log`（或 `Warning`，两者效果相同）跑一段时间，从应用日志里看有哪些授权命中了规则；清理完存量后再切 `Deny`。
:::

::: warning 违规检查发生在授权写入时，不是登录或请求时
约束规则只回答「能不能把这个角色授给这个人」，不参与请求期的鉴权判定。已经授出去的存量违规组合**不会自动回收**，系统也没有内置巡检，需要自行排查清理。
:::

## 怎么选

| 你的需求 | 用哪套 |
| --- | --- |
| 业务单据要人批（一步或多级、会签、分支、超时） | **审批中心**（由 [工作流](./workflow) 承载） |
| 「谁不能同时拥有哪些角色」这类合规规则 | **约束规则引擎** |
| 用户主动申请某个权限，管理员审批 | **权限申请**（`SysPermissionRequest`，提交即发起审批流，见 [权限模型](./permission)） |

约束规则与审批彼此独立：约束规则的 `RequireApproval` 不会发起审批，命中即阻断；需要「违规转审批」时，可让申请人走权限申请，审批通过授予时同样会做 SSD 校验。

## 相关页面

- [权限模型](./permission)：约束规则的当前执行范围、权限申请与委托
- [工作流](./workflow)：审批中心、受理人规则与审批业务接入
- [审计日志](./logging)：权限变更留痕
- [数据模型](./data-model#权限与授权)：相关表结构
