Skip to content

数据权限(@DataPermission)

迁移中 工作量最大的一处。

Java 侧做法

Java 用 @DataPermission 注解 + SpEL + MyBatis 拦截器动态拼 SQL,做部门 / 角色数据隔离。注解写在 service / mapper 方法上,运行时由拦截器解析 SpEL、按当前登录用户的角色数据范围(data_scope)拼出 WHERE 子句。

Go 侧做法

Go 无 SpEL 注解 + AOP 拦截器的等价机制。本项目在 repository 层用 GORM Scopes / Callback 手写数据权限过滤。

  • 数据权限是按角色配置的 SQL 片段(如「本部门」「本部门及以下」「全部」「自定义部门集」),存 sys_role.data_scope
  • 登录时把角色的数据范围解析成 LoginUser.DataScopeRoleMap,存进 sa-token session。
  • repository 层查询时取当前用户的 DataScopeRoleMap,按角色拼出 dept_id IN (...) 或直接放行(超管 / data_scope=1 全部)。

关键点

  • 超管短路LoginUser 是超管时直接放行,不拼任何条件(等价 Java data_scope=1 全部数据)。
  • 条件在 repository 拼:service 不感知数据权限,只把 ctx 传下去;repository 从 AuditUserFrom(ctx) 取登录用户,按其 DataScopeRoleMap 拼 GORM Scope。
  • 登录态经 ctx 接力:GORM 回调只拿得到 *gorm.DB,取不到 *gin.Context,故登录态由 loginhelper.AuditContext 中间件写进 request.ContextWithAuditUser),repository 用 AuditUserFrom(ctx) 取。详见 一次请求的流转

写新查询时的注意

  • @DataPermission 的列表查询(如 SelectAllocatedListSelectUnallocatedList)在 repository 层手写 Scope,别只写裸 WHERE
  • dest 常是 VO,不能拿 dest 反推表名(会打到不存在的表并丢逻辑删除条件),必须显式 Model(&entity)
  • Count / SelectList / SelectPageList 都要带 Model()del_flag 过滤由 LogicDelete 挂在字段类型上,须先解析出实体 schema 才生效。

详见 CRUD 指南 / Repository 与各模块 repository 源码(如 internal/system/repository/user_repository.goSelectAllocatedList / SelectPageList)。

基于 MIT 协议开源