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.Context(WithAuditUser),repository 用 AuditUserFrom(ctx) 取。详见 一次请求的流转。

写新查询时的注意 ​

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

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

基于 MIT 协议开源