Files
junhong_cmp_fiber/pkg/middleware/permission_helper.go
huang 03a0960c4d
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m2s
refactor: 数据权限过滤从 GORM Callback 改为 Store 层显式调用
- 移除 RegisterDataPermissionCallback 和 SkipDataPermission 机制
- 在 Auth 中间件预计算 SubordinateShopIDs 并注入 Context
- 新增 ApplyShopFilter/ApplyEnterpriseFilter/ApplyOwnerShopFilter 等 Helper 函数
- 所有 Store 层查询方法显式调用数据权限过滤函数
- 权限检查函数 CanManageShop/CanManageEnterprise 改为从 Context 获取数据

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-26 16:38:52 +08:00

96 lines
3.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}