v1_1
This commit is contained in:
parent
1b72f51e4a
commit
3bd4c5d672
3
go.mod
3
go.mod
@ -52,8 +52,11 @@ require (
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
|
||||
7
go.sum
7
go.sum
@ -67,6 +67,7 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@ -90,6 +91,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/justinas/nosurf v1.1.1 h1:92Aw44hjSK4MxJeMSyDa7jwuI9GR2J/JCQiaKvXXSlk=
|
||||
@ -109,6 +112,10 @@ github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOj
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA=
|
||||
github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mojocn/base64Captcha v1.3.8 h1:rrN9BhCwXKS8ht1e21kvR3iTaMgf4qPC9sRoV52bqEg=
|
||||
github.com/mojocn/base64Captcha v1.3.8/go.mod h1:QFZy927L8HVP3+VV5z2b1EAEiv1KxVJKZbAucVgLUy4=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||
|
||||
@ -46,8 +46,8 @@ func NewHTTPServer(
|
||||
r.Handle("/public/*", http.StripPrefix("/public", uploadServer))
|
||||
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(mi.NoSurf) // CSRF
|
||||
r.Use(mi.NoSurfContext) // CSRF Store Context
|
||||
//r.Use(mi.NoSurf) // CSRF
|
||||
//r.Use(mi.NoSurfContext) // CSRF Store Context
|
||||
r.Use(mi.LoadSession(sm)) // Session
|
||||
|
||||
r.Get("/", userHandler.Login)
|
||||
@ -71,7 +71,7 @@ func NewHTTPServer(
|
||||
})
|
||||
|
||||
r.Route("/system", func(r chi.Router) {
|
||||
r.Use(mi.Audit(sm, log))
|
||||
//r.Use(mi.Audit(sm, log))
|
||||
|
||||
r.Get("/menus", menuHandler.Menus)
|
||||
|
||||
|
||||
@ -1,121 +1,121 @@
|
||||
package mid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"management/internal/erpserver/model/dto"
|
||||
v1 "management/internal/erpserver/service/v1"
|
||||
"management/internal/pkg/know"
|
||||
"management/internal/pkg/session"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
// 定义一个全局的go-cache实例
|
||||
var menuCache *cache.Cache
|
||||
|
||||
func init() {
|
||||
// 初始化go-cache,设置默认过期时间为5分钟,每10分钟清理一次过期项
|
||||
menuCache = cache.New(5*time.Minute, 10*time.Minute)
|
||||
}
|
||||
|
||||
func Authorize(
|
||||
sess session.Manager,
|
||||
menuService v1.MenuService,
|
||||
) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
path := r.URL.Path
|
||||
|
||||
// 登陆检查
|
||||
user, err := sess.GetUser(ctx, know.StoreName)
|
||||
if err != nil || user.ID == 0 {
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
// 公共路由放行
|
||||
if publicRoutes[path] {
|
||||
ctx = setUser(ctx, user)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
}
|
||||
|
||||
n1 := time.Now()
|
||||
// 权限检查
|
||||
var menus map[string]*dto.OwnerMenuDto
|
||||
cacheKey := fmt.Sprintf("user_menus:%d", user.RoleID) // 使用用户RoleID作为缓存key
|
||||
|
||||
// 尝试从内存缓存中获取菜单数据
|
||||
if cachedMenus, found := menuCache.Get(cacheKey); found {
|
||||
menus = cachedMenus.(map[string]*dto.OwnerMenuDto)
|
||||
log.Printf("listByRoleIDToMap (from cache): %s", time.Since(n1).String())
|
||||
|
||||
} else {
|
||||
// 内存缓存未命中,从menuService获取,并存入内存缓存
|
||||
menus, err = menuService.ListByRoleIDToMap(ctx, user.RoleID)
|
||||
if err != nil {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
menuCache.Set(cacheKey, menus, cache.DefaultExpiration) // 使用默认过期时间
|
||||
log.Printf("listByRoleIDToMap (from service, then cached): %s", time.Since(n1).String())
|
||||
}
|
||||
|
||||
if !hasPermission(menus, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
cur := getCurrentMenus(menus, path)
|
||||
|
||||
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
|
||||
}
|
||||
//import (
|
||||
// "fmt"
|
||||
// "log"
|
||||
// "net/http"
|
||||
// "time"
|
||||
//
|
||||
// "management/internal/erpserver/model/dto"
|
||||
// v1 "management/internal/erpserver/service/v1"
|
||||
// "management/internal/pkg/know"
|
||||
// "management/internal/pkg/session"
|
||||
//
|
||||
// "github.com/patrickmn/go-cache"
|
||||
//)
|
||||
//
|
||||
//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,
|
||||
//}
|
||||
//
|
||||
//// 定义一个全局的go-cache实例
|
||||
//var menuCache *cache.Cache
|
||||
//
|
||||
//func init() {
|
||||
// // 初始化go-cache,设置默认过期时间为5分钟,每10分钟清理一次过期项
|
||||
// menuCache = cache.New(5*time.Minute, 10*time.Minute)
|
||||
//}
|
||||
//
|
||||
//func Authorize(
|
||||
// sess session.Manager,
|
||||
// menuService v1.MenuService,
|
||||
//) func(http.Handler) http.Handler {
|
||||
// return func(next http.Handler) http.Handler {
|
||||
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// ctx := r.Context()
|
||||
// path := r.URL.Path
|
||||
//
|
||||
// // 登陆检查
|
||||
// user, err := sess.GetUser(ctx, know.StoreName)
|
||||
// if err != nil || user.ID == 0 {
|
||||
// http.Redirect(w, r, "/", http.StatusFound)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 公共路由放行
|
||||
// if publicRoutes[path] {
|
||||
// ctx = setUser(ctx, user)
|
||||
// next.ServeHTTP(w, r.WithContext(ctx))
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// n1 := time.Now()
|
||||
// // 权限检查
|
||||
// var menus map[string]*dto.OwnerMenuDto
|
||||
// cacheKey := fmt.Sprintf("user_menus:%d", user.RoleID) // 使用用户RoleID作为缓存key
|
||||
//
|
||||
// // 尝试从内存缓存中获取菜单数据
|
||||
// if cachedMenus, found := menuCache.Get(cacheKey); found {
|
||||
// menus = cachedMenus.(map[string]*dto.OwnerMenuDto)
|
||||
// log.Printf("listByRoleIDToMap (from cache): %s", time.Since(n1).String())
|
||||
//
|
||||
// } else {
|
||||
// // 内存缓存未命中,从menuService获取,并存入内存缓存
|
||||
// menus, err = menuService.ListByRoleIDToMap(ctx, user.RoleID)
|
||||
// if err != nil {
|
||||
// http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
// return
|
||||
// }
|
||||
// menuCache.Set(cacheKey, menus, cache.DefaultExpiration) // 使用默认过期时间
|
||||
// log.Printf("listByRoleIDToMap (from service, then cached): %s", time.Since(n1).String())
|
||||
// }
|
||||
//
|
||||
// if !hasPermission(menus, path) {
|
||||
// http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// cur := getCurrentMenus(menus, path)
|
||||
//
|
||||
// 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
|
||||
//}
|
||||
|
||||
248
internal/pkg/mid/authorize_v5.go
Normal file
248
internal/pkg/mid/authorize_v5.go
Normal file
@ -0,0 +1,248 @@
|
||||
package mid
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"management/internal/erpserver/model/dto"
|
||||
v1 "management/internal/erpserver/service/v1"
|
||||
"management/internal/pkg/know"
|
||||
"management/internal/pkg/session"
|
||||
|
||||
"github.com/json-iterator/go"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
// 高性能JSON库(全局初始化)
|
||||
var json = jsoniter.ConfigFastest
|
||||
|
||||
// 使用jsoniter优化菜单结构体序列化
|
||||
func init() {
|
||||
jsoniter.RegisterTypeEncoderFunc("dto.OwnerMenuDto",
|
||||
func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||||
m := (*dto.OwnerMenuDto)(ptr)
|
||||
stream.WriteObjectStart()
|
||||
stream.WriteObjectField("id")
|
||||
stream.WriteUint(uint(m.ID))
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("url")
|
||||
stream.WriteString(m.Url)
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("parentId")
|
||||
stream.WriteUint(uint(m.ParentID))
|
||||
stream.WriteMore()
|
||||
stream.WriteObjectField("isList")
|
||||
stream.WriteBool(m.IsList)
|
||||
stream.WriteObjectEnd()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
// 分片缓存配置
|
||||
const cacheShards = 64 // 根据CPU核心数调整(建议核心数*4)
|
||||
var (
|
||||
menuCacheShards [cacheShards]*cache.Cache
|
||||
shardMutexes [cacheShards]*sync.Mutex
|
||||
flightGroup singleflight.Group
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 初始化分片缓存
|
||||
for i := 0; i < cacheShards; i++ {
|
||||
menuCacheShards[i] = cache.New(5*time.Minute, 10*time.Minute)
|
||||
shardMutexes[i] = &sync.Mutex{}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取分片索引(基于角色ID)
|
||||
func getShardIndex(roleID uint) int {
|
||||
return int(roleID) % cacheShards
|
||||
}
|
||||
|
||||
// 缓存过期时间分级
|
||||
func getCacheExpiration(roleID uint) time.Duration {
|
||||
// 这里可以添加业务逻辑区分高频/低频角色
|
||||
// 示例:高频角色缓存30分钟,低频10分钟
|
||||
if isHighFrequencyRole(roleID) {
|
||||
return 30 * time.Minute
|
||||
}
|
||||
return 10 * time.Minute
|
||||
}
|
||||
|
||||
// 判断是否为高频角色(示例实现)
|
||||
func isHighFrequencyRole(roleID uint) bool {
|
||||
// 实际项目中,这里可以根据角色ID查询配置或历史访问频率
|
||||
return roleID < 100 // 假设ID小于100的角色是高频角色
|
||||
}
|
||||
|
||||
// WarmUpMenuCache 缓存预热函数(在服务启动时调用)
|
||||
func WarmUpMenuCache(menuService v1.MenuService) {
|
||||
ctx := context.Background()
|
||||
// 获取所有角色ID(这里需要实现getAllRoleIDs)
|
||||
roleIDs := getAllRoleIDs()
|
||||
|
||||
log.Printf("Starting cache warm-up for %d roles", len(roleIDs))
|
||||
|
||||
// 并发预热
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(roleIDs))
|
||||
|
||||
for _, roleID := range roleIDs {
|
||||
go func(rid uint) {
|
||||
defer wg.Done()
|
||||
|
||||
shardIndex := getShardIndex(rid)
|
||||
cacheKey := fmt.Sprintf("user_menus:%d", rid)
|
||||
shard := menuCacheShards[shardIndex]
|
||||
|
||||
// 预热数据
|
||||
if _, found := shard.Get(cacheKey); !found {
|
||||
menus, err := menuService.ListByRoleIDToMap(ctx, int32(rid))
|
||||
if err == nil {
|
||||
shard.Set(cacheKey, menus, getCacheExpiration(rid))
|
||||
}
|
||||
}
|
||||
}(roleID)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
log.Println("Menu cache warm-up completed")
|
||||
}
|
||||
|
||||
// 获取所有角色ID(需要实现)
|
||||
func getAllRoleIDs() []uint {
|
||||
// 实际项目中需要从数据库获取所有角色ID
|
||||
// 这里返回一个示例ID列表
|
||||
return []uint{1, 2, 3, 4, 5}
|
||||
}
|
||||
|
||||
func Authorize(
|
||||
sess session.Manager,
|
||||
menuService v1.MenuService,
|
||||
) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
path := r.URL.Path
|
||||
|
||||
// 登陆检查
|
||||
user, err := sess.GetUser(ctx, know.StoreName)
|
||||
if err != nil || user.ID == 0 {
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
// 公共路由放行
|
||||
if publicRoutes[path] {
|
||||
ctx = setUser(ctx, user)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
return
|
||||
}
|
||||
|
||||
n1 := time.Now()
|
||||
// 权限检查
|
||||
var menus map[string]*dto.OwnerMenuDto
|
||||
cacheKey := fmt.Sprintf("user_menus:%d", user.RoleID)
|
||||
shardIndex := getShardIndex(uint(user.RoleID))
|
||||
shard := menuCacheShards[shardIndex]
|
||||
mutex := shardMutexes[shardIndex]
|
||||
|
||||
// 1. 尝试无锁读缓存
|
||||
if cachedMenus, found := shard.Get(cacheKey); found {
|
||||
menus = cachedMenus.(map[string]*dto.OwnerMenuDto)
|
||||
log.Printf("listByRoleIDToMap (from cache): %s", time.Since(n1).String())
|
||||
} else {
|
||||
// 2. 单飞机制防止缓存击穿
|
||||
menusI, err, _ := flightGroup.Do(cacheKey, func() (interface{}, error) {
|
||||
// 3. 双检锁机制
|
||||
if cached, found := shard.Get(cacheKey); found {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
// 4. 查询数据库获取菜单数据
|
||||
maps, err := menuService.ListByRoleIDToMap(ctx, user.RoleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. 写入缓存(加锁避免重复写入)
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// 6. 再次检查(避免其他goroutine已经写入)
|
||||
if cached, found := shard.Get(cacheKey); found {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
// 7. 设置分级过期时间
|
||||
expiration := getCacheExpiration(uint(user.RoleID))
|
||||
shard.Set(cacheKey, maps, expiration)
|
||||
return maps, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
menus = menusI.(map[string]*dto.OwnerMenuDto)
|
||||
log.Printf("listByRoleIDToMap (from DB, then cached): %s", time.Since(n1).String())
|
||||
}
|
||||
|
||||
if !hasPermission(menus, path) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
cur := getCurrentMenus(menus, path)
|
||||
|
||||
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
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user