package logic import ( "context" "github.com/gogf/gf/v2/database/gdb" "easygoadmin/internal/consts" "easygoadmin/internal/dao" ) // ============================== 角色数据权限(行级过滤) ============================== // // 档位(role.data_scope,多角色在身份加载层取最宽松): // 1-全部 租户隔离之内不过滤 // 2-本部门及以下 dept_id IN (自身部门 + 全部子孙部门) // 3-本部门 dept_id = 自身部门 // 4-仅本人 id = 自身用户ID // // 生效范围:挂接本函数的模块其 Page/List/导出(applyFilters 链)自动生效; // Detail/Update/Delete 不过滤,由 permission 节点与租户隔离兜底。 // 租户隔离、软删过滤由 dao.Ctx(hooks.ApplyCtx)先于本链注入,两层独立叠加。 // ApplyDataScope 数据权限过滤工厂 // // 返回可挂到 ModuleSpec.DataScope 的过滤函数;deptColumn 为行上的部门列名, // 无部门归属的行表(如内容模块)后续可按需提供按创建人过滤的变体。 func ApplyDataScope(deptColumn string) DataScopeFunc { return func(ctx context.Context, m *gdb.Model, req any) *gdb.Model { if dataScopeBypass(ctx) { return m } scope := consts.GetDataScope(ctx) if scope <= consts.DataScopeAll { return m } uid := consts.GetUserID(ctx) deptId := consts.GetDeptID(ctx) switch { case scope >= consts.DataScopeSelf || deptId <= 0: // 仅本人;未分配部门的用户挂部门档时降级为仅本人(安全兜底) return m.Where("id", uid) case scope == consts.DataScopeDept: return m.Where(deptColumn, deptId) case scope == consts.DataScopeDeptAndBelow: return m.WhereIn(deptColumn, deptSubtreeIds(ctx, deptId)) } return m } } // dataScopeBypass 数据范围豁免判断 // 平台级(超管)或持有超管角色编码时全量可见,与权限通配逻辑对齐 func dataScopeBypass(ctx context.Context) bool { if consts.IsPlatform(ctx) { return true } for _, r := range consts.GetRoles(ctx) { if r == consts.RoleCodeSuperAdmin { return true } } return false } // deptSubtreeIds 收集部门自身及全部子孙部门ID // // 部门为 parent_id 树且体量小,直接全量拉取后 BFS; // 查询经 dao.Ctx(租户隔离+软删),后续如成热点可加短时缓存 func deptSubtreeIds(ctx context.Context, deptId int) []int { rows, err := dao.Dept.Ctx(ctx).Fields("id, parent_id").All() if err != nil || len(rows) == 0 { return []int{deptId} } children := make(map[int][]int, len(rows)) for _, r := range rows { pid := r["parent_id"].Int() children[pid] = append(children[pid], r["id"].Int()) } ids := []int{deptId} for queue := []int{deptId}; len(queue) > 0; queue = queue[1:] { for _, cid := range children[queue[0]] { ids = append(ids, cid) queue = append(queue, cid) } } return ids }