|
|
|
@@ -0,0 +1,231 @@
|
|
|
|
|
// package handler
|
|
|
|
|
// @Link https://github.com/xiujiecn/xiu-admin
|
|
|
|
|
// @Copyright Copyright (c) 2025 LiXiujie
|
|
|
|
|
// @Author Lxj <xxx@example.com>
|
|
|
|
|
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
|
|
|
|
package handler
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
|
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
|
|
|
|
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert"
|
|
|
|
|
|
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
|
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
|
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
|
|
|
"github.com/gogf/gf/v2/util/gconv"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// FilterAuth 过滤数据权限
|
|
|
|
|
// 通过上下文中的用户角色权限和表中是否含有需要过滤的字段附加查询条件
|
|
|
|
|
func FilterAuth(m *gdb.Model) *gdb.Model {
|
|
|
|
|
var (
|
|
|
|
|
ctx = m.GetCtx()
|
|
|
|
|
fields = convert.EscapeFieldsToSlice(m.GetFieldsStr())
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 超管拥有全部权限
|
|
|
|
|
if contexts.IsSuperAdmin(ctx) {
|
|
|
|
|
return m
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取用户信息
|
|
|
|
|
user := contexts.GetUser(ctx)
|
|
|
|
|
if user == nil {
|
|
|
|
|
return m
|
|
|
|
|
}
|
|
|
|
|
if len(user.Roles) == 0 {
|
|
|
|
|
return m.Where("1 = 0")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deptIds := make([]int64, 0)
|
|
|
|
|
userIds := make([]int64, 0)
|
|
|
|
|
// 是否进入了非「全部数据」的受限范围;解析结果为空时必须拒绝,不能漏过滤
|
|
|
|
|
hasRestrictedScope := false
|
|
|
|
|
currentRoleId := ""
|
|
|
|
|
currentRoleDataScope := ""
|
|
|
|
|
currentRoleIdIf := contexts.GetDataValue(ctx, "currentRoleId")
|
|
|
|
|
if currentRoleIdIf != nil {
|
|
|
|
|
currentRoleId = currentRoleIdIf.(string)
|
|
|
|
|
}
|
|
|
|
|
currentRoleDataScopeIf := contexts.GetDataValue(ctx, "currentRoleDataScope")
|
|
|
|
|
if currentRoleDataScopeIf != nil {
|
|
|
|
|
currentRoleDataScope = currentRoleDataScopeIf.(string)
|
|
|
|
|
}
|
|
|
|
|
if len(currentRoleDataScope) > 0 && len(currentRoleId) > 0 {
|
|
|
|
|
dataScope := currentRoleDataScope
|
|
|
|
|
roleId := gconv.Int64(currentRoleId)
|
|
|
|
|
g.Log().Infof(ctx, "uid:%d, currentRoleId: %d, currentRoleDataScope: %s", user.ID, roleId, dataScope)
|
|
|
|
|
if dataScope == consts.SysRoleDataScopeAll { // 角色数据范围: 1全部数据权限
|
|
|
|
|
return m
|
|
|
|
|
}
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
if dataScope == consts.SysRoleDataScopeCustom { // 角色数据范围: 2自定数据权限
|
|
|
|
|
var roleDepts []*entity.SysRoleDept
|
|
|
|
|
err := g.Model("sys_role_dept").Where("tenant_id", contexts.GetTenantId(ctx)).Where("role_id", roleId).Scan(&roleDepts)
|
|
|
|
|
if err != nil {
|
|
|
|
|
g.Log().Panicf(ctx, "failed to get role dept data err:%+v", err)
|
|
|
|
|
}
|
|
|
|
|
for _, roleDept := range roleDepts {
|
|
|
|
|
deptIds = append(deptIds, roleDept.DeptId)
|
|
|
|
|
}
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeDept { // 角色数据范围: 3本部门数据权限
|
|
|
|
|
deptIds = append(deptIds, user.DeptId)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeDeptAndBelow { // 角色数据范围: 4本部门及以下数据权限
|
|
|
|
|
deptIds = append(deptIds, GetDeptAndSub(ctx, user.DeptId)...)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopePersonal { // 角色数据范围: 5仅本人数据权限
|
|
|
|
|
userIds = append(userIds, user.ID)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeDeptAndBelowOrPersonal { // 角色数据范围: 6本部门及以下或本人数据权限
|
|
|
|
|
deptIds = append(deptIds, GetDeptAndSub(ctx, user.DeptId)...)
|
|
|
|
|
userIds = append(userIds, user.ID)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeOrgAndNextLevel { // 角色数据范围: 7本组织及本组织下一级数据权限
|
|
|
|
|
deptIds = append(deptIds, GetOrgAndNextLevelDeptIds(ctx, user.DeptId)...)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeOrgNextLevel { // 角色数据范围: 8本组织下一级数据权限
|
|
|
|
|
deptIds = append(deptIds, GetOrgNextLevelDeptIds(ctx, user.DeptId)...)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
for _, role := range user.Roles {
|
|
|
|
|
dataScope := role.DataScope
|
|
|
|
|
roleId := role.RoleId
|
|
|
|
|
if dataScope == consts.SysRoleDataScopeAll { // 角色数据范围: 1全部数据权限
|
|
|
|
|
return m
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeCustom { // 角色数据范围: 2自定数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
var roleDepts []*entity.SysRoleDept
|
|
|
|
|
err := g.Model("sys_role_dept").Where("tenant_id", contexts.GetTenantId(ctx)).Where("role_id", roleId).Scan(&roleDepts)
|
|
|
|
|
if err != nil {
|
|
|
|
|
g.Log().Panicf(ctx, "failed to get role dept data err:%+v", err)
|
|
|
|
|
}
|
|
|
|
|
for _, roleDept := range roleDepts {
|
|
|
|
|
deptIds = append(deptIds, roleDept.DeptId)
|
|
|
|
|
}
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeDept { // 角色数据范围: 3本部门数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
deptIds = append(deptIds, user.DeptId)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeDeptAndBelow { // 角色数据范围: 4本部门及以下数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
deptIds = append(deptIds, GetDeptAndSub(ctx, user.DeptId)...)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopePersonal { // 角色数据范围: 5仅本人数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
userIds = append(userIds, user.ID)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeDeptAndBelowOrPersonal { // 角色数据范围: 6本部门及以下或本人数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
deptIds = append(deptIds, GetDeptAndSub(ctx, user.DeptId)...)
|
|
|
|
|
userIds = append(userIds, user.ID)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeOrgAndNextLevel { // 角色数据范围: 7本组织及本组织下一级数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
deptIds = append(deptIds, GetOrgAndNextLevelDeptIds(ctx, user.DeptId)...)
|
|
|
|
|
} else if dataScope == consts.SysRoleDataScopeOrgNextLevel { // 角色数据范围: 8本组织下一级数据权限
|
|
|
|
|
hasRestrictedScope = true
|
|
|
|
|
deptIds = append(deptIds, GetOrgNextLevelDeptIds(ctx, user.DeptId)...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deptFilterField := ""
|
|
|
|
|
if gstr.InArray(fields, "dept_id") {
|
|
|
|
|
deptFilterField = "dept_id"
|
|
|
|
|
} else if gstr.InArray(fields, "created_dept") {
|
|
|
|
|
deptFilterField = "created_dept"
|
|
|
|
|
}
|
|
|
|
|
userFilterField := ""
|
|
|
|
|
if gstr.InArray(fields, "user_id") {
|
|
|
|
|
userFilterField = "user_id"
|
|
|
|
|
} else if gstr.InArray(fields, "created_by") {
|
|
|
|
|
userFilterField = "created_by"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(deptIds) > 0 && len(userIds) > 0 {
|
|
|
|
|
if deptFilterField != "" && userFilterField != "" {
|
|
|
|
|
m = m.Where(deptFilterField+" IN (?) OR "+userFilterField+" IN (?)", deptIds, userIds)
|
|
|
|
|
} else if deptFilterField != "" {
|
|
|
|
|
m = m.WhereIn(deptFilterField, deptIds)
|
|
|
|
|
} else if userFilterField != "" {
|
|
|
|
|
m = m.WhereIn(userFilterField, userIds)
|
|
|
|
|
}
|
|
|
|
|
} else if len(deptIds) > 0 && deptFilterField != "" {
|
|
|
|
|
m = m.WhereIn(deptFilterField, deptIds)
|
|
|
|
|
} else if len(userIds) > 0 && userFilterField != "" {
|
|
|
|
|
m = m.WhereIn(userFilterField, userIds)
|
|
|
|
|
} else if hasRestrictedScope && (deptFilterField != "" || userFilterField != "") {
|
|
|
|
|
// 例:范围8无下级部门、范围2未配自定义部门 → 可见集合为空,禁止放行全表
|
|
|
|
|
g.Log().Warningf(ctx, "FilterAuth empty scope result, deny all data. uid:%d, deptIds:%v, userIds:%v", user.ID, deptIds, userIds)
|
|
|
|
|
m = m.Where("1 = 0")
|
|
|
|
|
}
|
|
|
|
|
return m
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetParentCompanyDeptId 获取用户所属上级公司组织ID
|
|
|
|
|
func GetParentCompanyDeptId(ctx context.Context, deptId int64) int64 {
|
|
|
|
|
if deptId <= 0 {
|
|
|
|
|
return deptId
|
|
|
|
|
}
|
|
|
|
|
var dept entity.SysDept
|
|
|
|
|
err := g.Model("sys_dept").Where("dept_id", deptId).Scan(&dept)
|
|
|
|
|
if err != nil || dept.DeptId == 0 {
|
|
|
|
|
return deptId
|
|
|
|
|
}
|
|
|
|
|
if dept.ParentId == 0 || dept.DeptType == 1 {
|
|
|
|
|
return dept.DeptId
|
|
|
|
|
}
|
|
|
|
|
return GetParentCompanyDeptId(ctx, dept.ParentId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetDeptDirectSub 获取指定部门的直接下级部门ID
|
|
|
|
|
func GetDeptDirectSub(ctx context.Context, deptId int64) (ids []int64) {
|
|
|
|
|
array, err := g.Model("sys_dept").
|
|
|
|
|
Where("parent_id", deptId).
|
|
|
|
|
Fields("dept_id").
|
|
|
|
|
Array()
|
|
|
|
|
if err != nil {
|
|
|
|
|
g.Log().Panicf(ctx, "GetDeptDirectSub err:%+v", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for _, v := range array {
|
|
|
|
|
ids = append(ids, v.Int64())
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetOrgAndNextLevelDeptIds 获取本组织及本组织下一级数据权限范围:所属公司组织及直接下级
|
|
|
|
|
func GetOrgAndNextLevelDeptIds(ctx context.Context, deptId int64) (ids []int64) {
|
|
|
|
|
orgDeptId := GetParentCompanyDeptId(ctx, deptId)
|
|
|
|
|
ids = append(ids, orgDeptId)
|
|
|
|
|
ids = append(ids, GetDeptDirectSub(ctx, orgDeptId)...)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetOrgNextLevelDeptIds 获取本组织下一级数据权限范围:所属公司组织的直接下级
|
|
|
|
|
func GetOrgNextLevelDeptIds(ctx context.Context, deptId int64) (ids []int64) {
|
|
|
|
|
orgDeptId := GetParentCompanyDeptId(ctx, deptId)
|
|
|
|
|
return GetDeptDirectSub(ctx, orgDeptId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetDeptAndSub 获取指定部门的所有下级,含本部门
|
|
|
|
|
//
|
|
|
|
|
// ancestors 的平台约定格式以逗号结尾(如 "0,1,172,"),但历史数据里存在
|
|
|
|
|
// 由代理建企业路径写入的缺尾逗号形态(如 "0,1,172")。两种都要匹配,
|
|
|
|
|
// 否则这些机构的下级会在「本机构及以下」数据权限展开时被整体漏掉,
|
|
|
|
|
// 表现为上级机构看不到下级(例:一级代理选不到划拨目标客户)。
|
|
|
|
|
func GetDeptAndSub(ctx context.Context, deptId int64) (ids []int64) {
|
|
|
|
|
// likeTail = "%,172"(机构在祖先链末尾)、likeInner = "%,172,%"(机构在祖先链中间)
|
|
|
|
|
likeTail := fmt.Sprintf("%%,%d", deptId)
|
|
|
|
|
array, err := g.Model("sys_dept").
|
|
|
|
|
Where("(ancestors LIKE ? OR ancestors LIKE ?)", likeTail+",%", likeTail).
|
|
|
|
|
Fields("dept_id").
|
|
|
|
|
Array()
|
|
|
|
|
if err != nil {
|
|
|
|
|
g.Log().Panicf(ctx, "GetDeptAndSub err:%+v", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, v := range array {
|
|
|
|
|
ids = append(ids, v.Int64())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ids = append(ids, deptId)
|
|
|
|
|
return
|
|
|
|
|
}
|