重构数据权限模型并清理旧RBAC代码
核心变更: - 数据权限过滤从基于账号层级改为基于用户类型的多策略过滤 - 移除 AccountStore 中的 GetSubordinateIDs 等旧方法 - 重构认证中间件,支持 enterprise_id 和 customer_id - 更新 GORM Callback,根据用户类型自动选择过滤策略(代理/企业/个人客户) - 更新所有集成测试以适配新的 API 签名 - 添加功能总结文档和 OpenSpec 归档 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,12 +52,12 @@ func Bootstrap(deps *Dependencies) (*BootstrapResult, error) {
|
||||
|
||||
// registerGORMCallbacks 注册 GORM Callbacks
|
||||
func registerGORMCallbacks(deps *Dependencies, stores *stores) error {
|
||||
// 注册数据权限过滤 Callback
|
||||
if err := pkgGorm.RegisterDataPermissionCallback(deps.DB, stores.Account); err != nil {
|
||||
// 注册数据权限过滤 Callback(使用 ShopStore 来查询下级店铺 ID)
|
||||
if err := pkgGorm.RegisterDataPermissionCallback(deps.DB, stores.Shop); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//注册自动添加创建&更新人 Clalback
|
||||
// 注册自动添加创建&更新人 Callback
|
||||
if err := pkgGorm.RegisterSetCreatorUpdaterCallback(deps.DB); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
// 注意:此结构体不导出,仅在 bootstrap 包内部使用
|
||||
type stores struct {
|
||||
Account *postgres.AccountStore
|
||||
Shop *postgres.ShopStore
|
||||
Role *postgres.RoleStore
|
||||
Permission *postgres.PermissionStore
|
||||
AccountRole *postgres.AccountRoleStore
|
||||
@@ -21,6 +22,7 @@ type stores struct {
|
||||
func initStores(deps *Dependencies) *stores {
|
||||
return &stores{
|
||||
Account: postgres.NewAccountStore(deps.DB, deps.Redis),
|
||||
Shop: postgres.NewShopStore(deps.DB, deps.Redis),
|
||||
Role: postgres.NewRoleStore(deps.DB),
|
||||
Permission: postgres.NewPermissionStore(deps.DB),
|
||||
AccountRole: postgres.NewAccountRoleStore(deps.DB),
|
||||
|
||||
@@ -171,9 +171,8 @@ func (s *Service) Delete(ctx context.Context, id uint) error {
|
||||
return fmt.Errorf("删除账号失败: %w", err)
|
||||
}
|
||||
|
||||
// TODO: 清除店铺的下级 ID 缓存(需要在 Service 层处理)
|
||||
// 由于账号层级关系改为通过 Shop 表维护,这里的缓存清理逻辑已废弃
|
||||
_ = s.accountStore.ClearSubordinatesCacheForParents(ctx, id)
|
||||
// 账号删除后不需要清理缓存
|
||||
// 数据权限过滤现在基于店铺层级,店铺相关的缓存清理由 ShopService 负责
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,13 +2,10 @@ package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/store"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@@ -133,67 +130,3 @@ func (s *AccountStore) List(ctx context.Context, opts *store.QueryOptions, filte
|
||||
return accounts, total, nil
|
||||
}
|
||||
|
||||
// GetSubordinateIDs 获取账号的所有可见账号 ID(包含自己)
|
||||
// 废弃说明:账号层级关系已改为通过 Shop 表维护
|
||||
// 新的数据权限过滤应该基于 ShopID,而非账号的 ParentID
|
||||
// 使用 Redis 缓存优化性能,缓存 30 分钟
|
||||
//
|
||||
// 对于代理账号:查询该账号所属店铺及其下级店铺的所有账号
|
||||
// 对于平台用户和超级管理员:返回空(在上层跳过过滤)
|
||||
func (s *AccountStore) GetSubordinateIDs(ctx context.Context, accountID uint) ([]uint, error) {
|
||||
// 1. 尝试从 Redis 缓存读取
|
||||
cacheKey := constants.RedisAccountSubordinatesKey(accountID)
|
||||
cached, err := s.redis.Get(ctx, cacheKey).Result()
|
||||
if err == nil {
|
||||
var ids []uint
|
||||
if err := sonic.Unmarshal([]byte(cached), &ids); err == nil {
|
||||
return ids, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 查询当前账号
|
||||
account, err := s.GetByID(ctx, accountID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. 如果是代理账号,需要查询该店铺及下级店铺的所有账号
|
||||
var ids []uint
|
||||
if account.UserType == constants.UserTypeAgent && account.ShopID != nil {
|
||||
// 注意:这里需要 ShopStore 来查询店铺的下级
|
||||
// 但为了避免循环依赖,这个逻辑应该在 Service 层处理
|
||||
// Store 层只提供基础的数据访问能力
|
||||
// 暂时返回只包含自己的列表
|
||||
ids = []uint{accountID}
|
||||
} else {
|
||||
// 平台用户和超级管理员返回空列表(在 Service 层跳过过滤)
|
||||
ids = []uint{}
|
||||
}
|
||||
|
||||
// 4. 写入 Redis 缓存(30 分钟过期)
|
||||
data, _ := sonic.Marshal(ids)
|
||||
s.redis.Set(ctx, cacheKey, data, 30*time.Minute)
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// ClearSubordinatesCache 清除指定账号的下级 ID 缓存
|
||||
func (s *AccountStore) ClearSubordinatesCache(ctx context.Context, accountID uint) error {
|
||||
cacheKey := constants.RedisAccountSubordinatesKey(accountID)
|
||||
return s.redis.Del(ctx, cacheKey).Err()
|
||||
}
|
||||
|
||||
// ClearSubordinatesCacheForParents 递归清除所有上级账号的缓存
|
||||
// 废弃说明:账号层级关系已改为通过 Shop 表维护
|
||||
// 新版本应该清除店铺层级的缓存,而非账号层级
|
||||
func (s *AccountStore) ClearSubordinatesCacheForParents(ctx context.Context, accountID uint) error {
|
||||
// 清除当前账号的缓存
|
||||
if err := s.ClearSubordinatesCache(ctx, accountID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: 应该清除该账号所属店铺及上级店铺的下级缓存
|
||||
// 但这需要访问 ShopStore,为了避免循环依赖,应在 Service 层处理
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user