All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m2s
- 移除 RegisterDataPermissionCallback 和 SkipDataPermission 机制 - 在 Auth 中间件预计算 SubordinateShopIDs 并注入 Context - 新增 ApplyShopFilter/ApplyEnterpriseFilter/ApplyOwnerShopFilter 等 Helper 函数 - 所有 Store 层查询方法显式调用数据权限过滤函数 - 权限检查函数 CanManageShop/CanManageEnterprise 改为从 Context 获取数据 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
96 lines
3.1 KiB
Go
96 lines
3.1 KiB
Go
package middleware
|
||
|
||
import (
|
||
"context"
|
||
"slices"
|
||
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// EnterpriseStoreInterface 企业存储接口
|
||
// 用于权限检查时查询企业信息
|
||
type EnterpriseStoreInterface interface {
|
||
GetByID(ctx context.Context, id uint) (*model.Enterprise, error)
|
||
GetByIDs(ctx context.Context, ids []uint) ([]*model.Enterprise, error)
|
||
}
|
||
|
||
// CanManageShop 检查当前用户是否有权管理目标店铺
|
||
// 超级管理员和平台用户自动通过(SubordinateShopIDs 为 nil)
|
||
// 代理账号只能管理自己店铺及下级店铺
|
||
// 企业账号禁止管理店铺
|
||
func CanManageShop(ctx context.Context, targetShopID uint) error {
|
||
userType := GetUserTypeFromContext(ctx)
|
||
|
||
// 企业账号禁止管理店铺
|
||
if userType == constants.UserTypeEnterprise {
|
||
return errors.New(errors.CodeForbidden, "无权限管理店铺")
|
||
}
|
||
|
||
// 从 Context 获取预计算的下级店铺 ID 列表
|
||
subordinateIDs := GetSubordinateShopIDs(ctx)
|
||
|
||
// nil 表示不受限制(超级管理员/平台用户)
|
||
if subordinateIDs == nil {
|
||
return nil
|
||
}
|
||
|
||
// 检查目标店铺是否在下级列表中
|
||
if slices.Contains(subordinateIDs, targetShopID) {
|
||
return nil
|
||
}
|
||
|
||
return errors.New(errors.CodeForbidden, "无权限管理该店铺")
|
||
}
|
||
|
||
// CanManageEnterprise 检查当前用户是否有权管理目标企业
|
||
// 超级管理员和平台用户自动通过(SubordinateShopIDs 为 nil)
|
||
// 代理账号只能管理归属于自己店铺或下级店铺的企业
|
||
// 企业账号禁止管理其他企业
|
||
func CanManageEnterprise(ctx context.Context, targetEnterpriseID uint, enterpriseStore EnterpriseStoreInterface) error {
|
||
userType := GetUserTypeFromContext(ctx)
|
||
|
||
// 企业账号禁止管理其他企业
|
||
if userType == constants.UserTypeEnterprise {
|
||
return errors.New(errors.CodeForbidden, "无权限管理企业")
|
||
}
|
||
|
||
// 从 Context 获取预计算的下级店铺 ID 列表
|
||
subordinateIDs := GetSubordinateShopIDs(ctx)
|
||
|
||
// nil 表示不受限制(超级管理员/平台用户)
|
||
if subordinateIDs == nil {
|
||
return nil
|
||
}
|
||
|
||
// 获取目标企业信息
|
||
enterprise, err := enterpriseStore.GetByID(ctx, targetEnterpriseID)
|
||
if err != nil {
|
||
return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
|
||
}
|
||
|
||
// 代理账号不能管理平台级企业(owner_shop_id 为 NULL)
|
||
if enterprise.OwnerShopID == nil {
|
||
return errors.New(errors.CodeForbidden, "无权限管理平台级企业")
|
||
}
|
||
|
||
// 检查企业归属的店铺是否在下级列表中
|
||
if slices.Contains(subordinateIDs, *enterprise.OwnerShopID) {
|
||
return nil
|
||
}
|
||
|
||
return errors.New(errors.CodeForbidden, "无权限管理该企业")
|
||
}
|
||
|
||
// ContainsShopID 检查目标店铺 ID 是否在当前用户可管理的店铺列表中
|
||
// 平台用户/超管返回 true(不受限制)
|
||
// 代理用户检查是否在 SubordinateShopIDs 中
|
||
func ContainsShopID(ctx context.Context, targetShopID uint) bool {
|
||
subordinateIDs := GetSubordinateShopIDs(ctx)
|
||
if subordinateIDs == nil {
|
||
return true // 不受限制
|
||
}
|
||
return slices.Contains(subordinateIDs, targetShopID)
|
||
}
|