v1
This commit is contained in:
402
internal/pkg/mid/authorize_v2.go
Normal file
402
internal/pkg/mid/authorize_v2.go
Normal file
@@ -0,0 +1,402 @@
|
||||
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
|
||||
//}
|
||||
Reference in New Issue
Block a user