Files
junhong_cmp_fiber/pkg/middleware/permission_helper.go
huang 80f560df33
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
refactor(account): 统一账号管理API、完善权限检查和操作审计
- 合并 customer_account 和 shop_account 路由到统一的 account 接口
- 新增统一认证接口 (auth handler)
- 实现越权防护中间件和权限检查工具函数
- 新增操作审计日志模型和服务
- 更新数据库迁移 (版本 39: account_operation_log 表)
- 补充集成测试覆盖权限检查和审计日志场景
2026-02-02 17:23:20 +08:00

112 lines
3.7 KiB
Go
Raw 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"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
)
// ShopStoreInterface 店铺存储接口
// 用于权限检查时查询店铺信息和下级店铺ID
type ShopStoreInterface interface {
GetByID(ctx context.Context, id uint) (*model.Shop, error)
GetSubordinateShopIDs(ctx context.Context, shopID uint) ([]uint, error)
}
// EnterpriseStoreInterface 企业存储接口
// 用于权限检查时查询企业信息
type EnterpriseStoreInterface interface {
GetByID(ctx context.Context, id uint) (*model.Enterprise, error)
}
// CanManageShop 检查当前用户是否有权管理目标店铺的账号
// 超级管理员和平台用户自动通过
// 代理账号只能管理自己店铺及下级店铺的账号
// 企业账号禁止管理店铺账号
func CanManageShop(ctx context.Context, targetShopID uint, shopStore ShopStoreInterface) error {
userType := GetUserTypeFromContext(ctx)
// 超级管理员和平台用户跳过权限检查
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
return nil
}
// 企业账号禁止管理店铺账号
if userType != constants.UserTypeAgent {
return errors.New(errors.CodeForbidden, "无权限管理店铺账号")
}
// 获取当前代理账号的店铺ID
currentShopID := GetShopIDFromContext(ctx)
if currentShopID == 0 {
return errors.New(errors.CodeForbidden, "无权限管理店铺账号")
}
// 递归查询下级店铺ID包含自己
subordinateIDs, err := shopStore.GetSubordinateShopIDs(ctx, currentShopID)
if err != nil {
return errors.Wrap(errors.CodeInternalError, err, "查询下级店铺失败")
}
// 检查目标店铺是否在下级列表中
for _, id := range subordinateIDs {
if id == targetShopID {
return nil
}
}
return errors.New(errors.CodeForbidden, "无权限管理该店铺的账号")
}
// CanManageEnterprise 检查当前用户是否有权管理目标企业的账号
// 超级管理员和平台用户自动通过
// 代理账号只能管理归属于自己店铺或下级店铺的企业账号
// 企业账号禁止管理其他企业账号
func CanManageEnterprise(ctx context.Context, targetEnterpriseID uint, enterpriseStore EnterpriseStoreInterface, shopStore ShopStoreInterface) error {
userType := GetUserTypeFromContext(ctx)
// 超级管理员和平台用户跳过权限检查
if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
return nil
}
// 企业账号禁止管理其他企业账号
if userType != constants.UserTypeAgent {
return errors.New(errors.CodeForbidden, "无权限管理企业账号")
}
// 获取目标企业信息
enterprise, err := enterpriseStore.GetByID(ctx, targetEnterpriseID)
if err != nil {
return errors.Wrap(errors.CodeForbidden, err, "无权限操作该资源或资源不存在")
}
// 代理账号不能管理平台级企业owner_shop_id为NULL
if enterprise.OwnerShopID == nil {
return errors.New(errors.CodeForbidden, "无权限管理平台级企业账号")
}
// 获取当前代理账号的店铺ID
currentShopID := GetShopIDFromContext(ctx)
if currentShopID == 0 {
return errors.New(errors.CodeForbidden, "无权限管理企业账号")
}
// 递归查询下级店铺ID包含自己
subordinateIDs, err := shopStore.GetSubordinateShopIDs(ctx, currentShopID)
if err != nil {
return errors.Wrap(errors.CodeInternalError, err, "查询下级店铺失败")
}
// 检查企业归属的店铺是否在下级列表中
for _, id := range subordinateIDs {
if id == *enterprise.OwnerShopID {
return nil
}
}
return errors.New(errors.CodeForbidden, "无权限管理该企业的账号")
}