71 lines
1.6 KiB
Go
71 lines
1.6 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"hfb_sys/backend/pkg/response"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// RequirePermission 检查当前管理员是否拥有指定权限。
|
|
// 超级管理员(拥有 super_admin 角色的管理员)自动放行。
|
|
func RequirePermission(permCode string, rdb *redis.Client) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
value, ok := c.Get(ContextAdminID)
|
|
if !ok {
|
|
response.Unauthorized(c, "缺少管理员上下文")
|
|
c.Abort()
|
|
return
|
|
}
|
|
adminID, ok := value.(uint64)
|
|
if !ok {
|
|
response.Unauthorized(c, "管理员上下文无效")
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
codes, err := getPermCodes(c, rdb, adminID)
|
|
if err != nil {
|
|
response.Error(c, http.StatusInternalServerError, "perm_check_failed", "权限校验服务暂时不可用")
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
for _, code := range codes {
|
|
if code == permCode || code == "*" {
|
|
c.Next()
|
|
return
|
|
}
|
|
}
|
|
|
|
response.Error(c, http.StatusForbidden, "forbidden", "没有操作权限")
|
|
c.Abort()
|
|
}
|
|
}
|
|
|
|
func getPermCodes(c *gin.Context, rdb *redis.Client, adminID uint64) ([]string, error) {
|
|
if rdb == nil {
|
|
return nil, errors.New("redis unavailable")
|
|
}
|
|
ctx := context.Background()
|
|
key := fmt.Sprintf("admin:perms:%d", adminID)
|
|
raw, err := rdb.Get(ctx, key).Result()
|
|
if errors.Is(err, redis.Nil) {
|
|
return nil, nil // 缓存未命中,视为无权限
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var codes []string
|
|
if err := json.Unmarshal([]byte(raw), &codes); err != nil {
|
|
return nil, err
|
|
}
|
|
return codes, nil
|
|
}
|