projectx/internal/pkg/mid/authorize_v2.go
2025-06-13 17:23:16 +08:00

403 lines
9.8 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 mid
//
//import (
// "context"
// "log"
// "net/http"
// "sync"
// "time"
//
// "management/internal/erpserver/model/dto"
// v1 "management/internal/erpserver/service/v1"
// "management/internal/pkg/know"
// "management/internal/pkg/session"
//)
//
//var publicRoutes = map[string]bool{
// "/home.html": true,
// "/dashboard": true,
// "/system/menus": true,
// "/upload/img": true,
// "/upload/file": true,
// "/upload/multi_files": true,
// "/pear.json": true,
// "/logout": true,
//}
//
//// MenuCacheItem 菜单缓存项
//type MenuCacheItem struct {
// Data map[string]*dto.OwnerMenuDto
// ExpireAt time.Time
// LoadTime time.Time
// Version int64
//}
//
//// IsExpired 检查是否过期
//func (item *MenuCacheItem) IsExpired() bool {
// return time.Now().After(item.ExpireAt)
//}
//
//// MenuCache 内存缓存管理器
//type MenuCache struct {
// mu sync.RWMutex
// cache map[int32]*MenuCacheItem // roleID -> MenuCacheItem
// maxSize int // 最大缓存条目数
// ttl time.Duration // 缓存TTL
// refreshTTL time.Duration // 刷新TTL (提前刷新时间)
// stats CacheStats // 缓存统计
// cleanupTick *time.Ticker // 清理定时器
// stopCh chan struct{} // 停止信号
//}
//
//// CacheStats 缓存统计信息
//type CacheStats struct {
// mu sync.RWMutex
// Hits int64
// Misses int64
// Evictions int64
// RefreshCount int64
//}
//
//// NewMenuCache 创建新的菜单缓存
//func NewMenuCache(maxSize int, ttl time.Duration) *MenuCache {
// cache := &MenuCache{
// cache: make(map[int32]*MenuCacheItem),
// maxSize: maxSize,
// ttl: ttl,
// refreshTTL: ttl - time.Duration(float64(ttl)*0.1), // 提前10%刷新
// stopCh: make(chan struct{}),
// cleanupTick: time.NewTicker(time.Minute * 5), // 每5分钟清理一次
// }
//
// // 启动后台清理协程
// go cache.cleanup()
//
// return cache
//}
//
//// Get 获取缓存数据
//func (mc *MenuCache) Get(roleID int32) (map[string]*dto.OwnerMenuDto, bool) {
// mc.mu.RLock()
// item, exists := mc.cache[roleID]
// mc.mu.RUnlock()
//
// if !exists {
// mc.recordMiss()
// return nil, false
// }
//
// // 检查是否过期
// if item.IsExpired() {
// mc.recordMiss()
// // 异步删除过期项
// go func() {
// mc.mu.Lock()
// delete(mc.cache, roleID)
// mc.mu.Unlock()
// }()
// return nil, false
// }
//
// mc.recordHit()
// return item.Data, true
//}
//
//// Set 设置缓存数据
//func (mc *MenuCache) Set(roleID int32, data map[string]*dto.OwnerMenuDto, version int64) {
// mc.mu.Lock()
// defer mc.mu.Unlock()
//
// // 如果缓存已满执行LRU淘汰
// if len(mc.cache) >= mc.maxSize {
// mc.evictLRU()
// }
//
// item := &MenuCacheItem{
// Data: data,
// ExpireAt: time.Now().Add(mc.ttl),
// LoadTime: time.Now(),
// Version: version,
// }
//
// mc.cache[roleID] = item
//}
//
//// NeedRefresh 检查是否需要提前刷新
//func (mc *MenuCache) NeedRefresh(roleID int32) bool {
// mc.mu.RLock()
// item, exists := mc.cache[roleID]
// mc.mu.RUnlock()
//
// if !exists {
// return true
// }
//
// // 提前刷新策略在过期前10%时间开始刷新
// refreshTime := item.LoadTime.Add(mc.refreshTTL)
// return time.Now().After(refreshTime)
//}
//
//// evictLRU 淘汰最久未使用的缓存项
//func (mc *MenuCache) evictLRU() {
// var oldestRoleID int32
// var oldestTime time.Time = time.Now()
//
// for roleID, item := range mc.cache {
// if item.LoadTime.Before(oldestTime) {
// oldestTime = item.LoadTime
// oldestRoleID = roleID
// }
// }
//
// if oldestRoleID != 0 {
// delete(mc.cache, oldestRoleID)
// mc.stats.mu.Lock()
// mc.stats.Evictions++
// mc.stats.mu.Unlock()
// }
//}
//
//// cleanup 后台清理过期缓存
//func (mc *MenuCache) cleanup() {
// for {
// select {
// case <-mc.cleanupTick.C:
// mc.cleanupExpired()
// case <-mc.stopCh:
// mc.cleanupTick.Stop()
// return
// }
// }
//}
//
//// cleanupExpired 清理过期缓存
//func (mc *MenuCache) cleanupExpired() {
// mc.mu.Lock()
// defer mc.mu.Unlock()
//
// now := time.Now()
// for roleID, item := range mc.cache {
// if now.After(item.ExpireAt) {
// delete(mc.cache, roleID)
// }
// }
//}
//
//// GetStats 获取缓存统计信息
//func (mc *MenuCache) GetStats() CacheStats {
// mc.stats.mu.RLock()
// defer mc.stats.mu.RUnlock()
// return mc.stats
//}
//
//// recordHit 记录缓存命中
//func (mc *MenuCache) recordHit() {
// mc.stats.mu.Lock()
// mc.stats.Hits++
// mc.stats.mu.Unlock()
//}
//
//// recordMiss 记录缓存未命中
//func (mc *MenuCache) recordMiss() {
// mc.stats.mu.Lock()
// mc.stats.Misses++
// mc.stats.mu.Unlock()
//}
//
//// Close 关闭缓存
//func (mc *MenuCache) Close() {
// close(mc.stopCh)
//}
//
//// CachedMenuService 带缓存的菜单服务包装器
//type CachedMenuService struct {
// menuService v1.MenuService
// cache *MenuCache
// mu sync.RWMutex
// refreshing map[int32]bool // 正在刷新的roleID
//}
//
//// NewCachedMenuService 创建带缓存的菜单服务
//func NewCachedMenuService(menuService v1.MenuService, cache *MenuCache) *CachedMenuService {
// return &CachedMenuService{
// menuService: menuService,
// cache: cache,
// refreshing: make(map[int32]bool),
// }
//}
//
//// ListByRoleIDToMap 获取菜单数据(带缓存)
//func (cms *CachedMenuService) ListByRoleIDToMap(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
// // 先尝试从缓存获取
// if data, hit := cms.cache.Get(roleID); hit {
// // 检查是否需要异步刷新
// if cms.cache.NeedRefresh(roleID) {
// go cms.asyncRefresh(ctx, roleID)
// }
// return data, nil
// }
//
// // 缓存未命中,同步获取数据
// return cms.loadAndCache(ctx, roleID)
//}
//
//// loadAndCache 加载数据并缓存
//func (cms *CachedMenuService) loadAndCache(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
// // 防止并发重复加载
// cms.mu.Lock()
// if cms.refreshing[roleID] {
// cms.mu.Unlock()
// // 如果正在加载,等待一小段时间后重试缓存
// time.Sleep(time.Millisecond * 10)
// if data, hit := cms.cache.Get(roleID); hit {
// return data, nil
// }
// // 重试失败,继续执行加载逻辑
// cms.mu.Lock()
// }
// cms.refreshing[roleID] = true
// cms.mu.Unlock()
//
// defer func() {
// cms.mu.Lock()
// delete(cms.refreshing, roleID)
// cms.mu.Unlock()
// }()
//
// // 从原始服务获取数据
// data, err := cms.menuService.ListByRoleIDToMap(ctx, roleID)
// if err != nil {
// return nil, err
// }
//
// // 缓存数据
// version := time.Now().UnixNano()
// cms.cache.Set(roleID, data, version)
//
// return data, nil
//}
//
//// asyncRefresh 异步刷新缓存
//func (cms *CachedMenuService) asyncRefresh(ctx context.Context, roleID int32) {
// // 使用背景上下文,避免原请求取消影响刷新
// bgCtx := context.Background()
//
// cms.mu.RLock()
// if cms.refreshing[roleID] {
// cms.mu.RUnlock()
// return
// }
// cms.mu.RUnlock()
//
// _, err := cms.loadAndCache(bgCtx, roleID)
// if err != nil {
// log.Printf("async refresh menu cache failed for roleID %d: %v", roleID, err)
// }
//
// cms.cache.stats.mu.Lock()
// cms.cache.stats.RefreshCount++
// cms.cache.stats.mu.Unlock()
//}
//
//// 全局缓存实例
//var (
// menuCache *MenuCache
// cachedMenuSvc *CachedMenuService
// cacheInitOnce sync.Once
//)
//
//// InitMenuCache 初始化菜单缓存(在应用启动时调用)
//func InitMenuCache(menuService v1.MenuService) {
// cacheInitOnce.Do(func() {
// // 配置参数最大1000个角色的缓存TTL 10分钟
// menuCache = NewMenuCache(1000, time.Minute*10)
// cachedMenuSvc = NewCachedMenuService(menuService, menuCache)
// })
//}
//
//// GetCachedMenuService 获取缓存菜单服务实例
//func GetCachedMenuService() *CachedMenuService {
// return cachedMenuSvc
//}
//
//// Authorize 修改后的授权中间件
//func Authorize(
// sess session.Manager,
// menuService v1.MenuService,
//) func(http.Handler) http.Handler {
// // 初始化缓存
// InitMenuCache(menuService)
//
// return func(next http.Handler) http.Handler {
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ctx := r.Context()
// path := r.URL.Path
//
// // 登陆检查
// n := time.Now()
// user, err := sess.GetUser(ctx, know.StoreName)
// if err != nil || user.ID == 0 {
// http.Redirect(w, r, "/", http.StatusFound)
// return
// }
//
// log.Printf("scs get user: %s", time.Since(n).String())
//
// // 公共路由放行
// if publicRoutes[path] {
// ctx = setUser(ctx, user)
// next.ServeHTTP(w, r.WithContext(ctx))
// return
// }
//
// n1 := time.Now()
// // 权限检查 - 使用缓存服务
// menus, err := GetCachedMenuService().ListByRoleIDToMap(ctx, user.RoleID)
// if err != nil || !hasPermission(menus, path) {
// http.Error(w, "Forbidden", http.StatusForbidden)
// return
// }
//
// log.Printf("listByRoleIDToMap (cached): %s", time.Since(n1).String())
//
// n2 := time.Now()
// cur := getCurrentMenus(menus, path)
// log.Printf("getCurrentMenus: %s", time.Since(n2).String())
//
// ctx = setUser(ctx, user)
// ctx = setCurMenus(ctx, cur)
//
// next.ServeHTTP(w, r.WithContext(ctx))
// })
// }
//}
//
//func hasPermission(menus map[string]*dto.OwnerMenuDto, path string) bool {
// _, ok := menus[path]
// return ok
//}
//
//func getCurrentMenus(data map[string]*dto.OwnerMenuDto, path string) []dto.OwnerMenuDto {
// var res []dto.OwnerMenuDto
//
// menu, ok := data[path]
// if !ok {
// return res
// }
//
// for _, item := range data {
// if menu.IsList {
// if item.ParentID == menu.ID || item.ID == menu.ID {
// res = append(res, *item)
// }
// } else {
// if item.ParentID == menu.ParentID {
// res = append(res, *item)
// }
// }
// }
//
// return res
//}