package middleware import ( "net/http" "sync" "time" "silk-server-go/internal/model" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // rolePermCache 角色-权限码缓存,避免每次请求查库 var ( rolePermCache = make(map[string]map[string]bool) rolePermCacheMu sync.RWMutex rolePermCacheTime time.Time ) const rolePermCacheTTL = 5 * time.Minute // loadRolePermissions 从数据库加载所有角色-权限映射到缓存 func loadRolePermissions(db *gorm.DB) map[string]map[string]bool { result := make(map[string]map[string]bool) var rows []struct { Role string `gorm:"column:role"` Code string `gorm:"column:code"` } db.Table("role_permissions"). Select("role_permissions.role AS role, permissions.code AS code"). Joins("JOIN permissions ON permissions.id = role_permissions.permission_id"). Scan(&rows) for _, r := range rows { if result[r.Role] == nil { result[r.Role] = make(map[string]bool) } result[r.Role][r.Code] = true } return result } // getRolePermissions 获取缓存的角色权限映射(TTL 5 分钟) func getRolePermissions(db *gorm.DB) map[string]map[string]bool { rolePermCacheMu.RLock() if time.Since(rolePermCacheTime) < rolePermCacheTTL && len(rolePermCache) > 0 { cached := rolePermCache rolePermCacheMu.RUnlock() return cached } rolePermCacheMu.RUnlock() rolePermCacheMu.Lock() defer rolePermCacheMu.Unlock() // 双重检查 if time.Since(rolePermCacheTime) < rolePermCacheTTL && len(rolePermCache) > 0 { return rolePermCache } rolePermCache = loadRolePermissions(db) rolePermCacheTime = time.Now() return rolePermCache } // InvalidateRolePermCache 使角色权限缓存失效(角色权限变更时调用) func InvalidateRolePermCache() { rolePermCacheMu.Lock() defer rolePermCacheMu.Unlock() rolePermCache = make(map[string]map[string]bool) rolePermCacheTime = time.Time{} } // hasPermission 检查角色是否拥有指定权限码 func hasPermission(db *gorm.DB, role, code string) bool { perms := getRolePermissions(db) rolePerms, ok := perms[role] if !ok { return false } return rolePerms[code] } // RequirePermission 返回一个校验指定权限码的中间件 func RequirePermission(db *gorm.DB, code string) gin.HandlerFunc { return func(c *gin.Context) { userVal, exists := c.Get("user") if !exists { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "未认证"}) return } userMap, ok := userVal.(map[string]interface{}) if !ok { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "权限不足"}) return } role, _ := userMap["role"].(string) if role == model.RoleAdmin { // admin 拥有全部权限,直接放行 c.Next() return } if !hasPermission(db, role, code) { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "权限不足,需要:" + code}) return } c.Next() } }