110 lines
2.8 KiB
Go
110 lines
2.8 KiB
Go
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()
|
|
}
|
|
}
|