fix: cache admin permissions in redis

This commit is contained in:
richjohnrambo
2026-09-23 00:30:40 +08:00
parent 4fbc896d75
commit dd12dbfe07
3 changed files with 129 additions and 26 deletions
+110 -16
View File
@@ -10,13 +10,18 @@ import (
"fmt"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/cache"
"net/http"
"regexp"
"strings"
"time"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model"
casbinutil "github.com/casbin/casbin/v2/util"
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
@@ -33,6 +38,14 @@ const (
var Enforcer *casbin.Enforcer
const permissionCacheKey = "admin:role:permissions"
type PermissionPolicy struct {
Key string `json:"key"`
Perm string `json:"perm"`
ActRegexp string `json:"actRegexp"`
}
// InitEnforcer 初始化
func InitEnforcer(ctx context.Context) {
var (
@@ -69,6 +82,9 @@ func InitEnforcer(ctx context.Context) {
g.Log().Panicf(ctx, "casbin NewEnforcer err:%v", err)
}
loadPermissions(ctx)
if err = RefreshPermissionCache(ctx); err != nil {
g.Log().Panicf(ctx, "casbin RefreshPermissionCache err:%v", err)
}
}
// GetDbLink 获取数据库链接
@@ -91,15 +107,13 @@ func getDbLink(ctx context.Context) *gvar.Var {
}
func loadPermissions(ctx context.Context) {
type Policy struct {
func queryPermissionPolicies(ctx context.Context) (policies []*PermissionPolicy, err error) {
type RolePermission struct {
Key string `json:"key"`
Permissions string `json:"permissions"`
}
var (
rules [][]string
polices []*Policy
err error
records []*RolePermission
)
//别名拼接 r.key m.permissions
q := func(alias string, column string) string {
@@ -113,23 +127,43 @@ func loadPermissions(ctx context.Context) {
Where(q("m", dao.AdminMenu.Columns().Status), consts.StatusEnabled).
WhereNot(q("m", dao.AdminMenu.Columns().Permissions), "").
WhereNot(q("r", dao.AdminRole.Columns().Key), consts.SuperRoleKey).
Scan(&polices)
Scan(&records)
if err != nil {
return nil, err
}
for _, record := range records {
if strings.Contains(record.Permissions, ",") {
lst := strings.Split(record.Permissions, ",")
for _, permission := range lst {
permission = strings.TrimSpace(permission)
if permission == "" {
continue
}
policies = append(policies, &PermissionPolicy{Key: record.Key, Perm: permission, ActRegexp: ActionAll})
}
} else {
permission := strings.TrimSpace(record.Permissions)
if permission == "" {
continue
}
policies = append(policies, &PermissionPolicy{Key: record.Key, Perm: permission, ActRegexp: ActionAll})
}
}
return
}
func loadPermissions(ctx context.Context) {
policies, err := queryPermissionPolicies(ctx)
if err != nil {
g.Log().Fatalf(ctx, "loadPermissions Scan err:%v", err)
return
}
for _, policy := range polices {
if strings.Contains(policy.Permissions, ",") {
lst := strings.Split(policy.Permissions, ",")
for _, permissions := range lst {
rules = append(rules, []string{policy.Key, permissions, ActionAll})
}
} else {
rules = append(rules, []string{policy.Key, policy.Permissions, ActionAll})
}
rules := make([][]string, 0, len(policies))
for _, policy := range policies {
rules = append(rules, []string{policy.Key, policy.Perm, policy.ActRegexp})
}
if _, err = Enforcer.AddPolicies(rules); err != nil {
g.Log().Fatalf(ctx, "loadPermissions AddPolicies err:%v", err)
return
@@ -160,5 +194,65 @@ func Refresh(ctx context.Context) (err error) {
return err
}
loadPermissions(ctx)
return RefreshPermissionCache(ctx)
}
func RefreshPermissionCache(ctx context.Context) (err error) {
policies, err := queryPermissionPolicies(ctx)
if err != nil {
return err
}
rolePolicies := make(map[string][]*PermissionPolicy)
for _, policy := range policies {
rolePolicies[policy.Key] = append(rolePolicies[policy.Key], policy)
}
data, err := gjson.Encode(rolePolicies)
if err != nil {
return err
}
return cache.Instance().Set(ctx, permissionCacheKey, string(data), 30*24*time.Hour)
}
func cachedPermissionPolicies(ctx context.Context) (rolePolicies map[string][]*PermissionPolicy, err error) {
value, err := cache.Instance().Get(ctx, permissionCacheKey)
if err != nil {
return nil, err
}
if value.IsNil() {
if err = RefreshPermissionCache(ctx); err != nil {
return nil, err
}
value, err = cache.Instance().Get(ctx, permissionCacheKey)
if err != nil {
return nil, err
}
}
rolePolicies = make(map[string][]*PermissionPolicy)
if value.IsNil() {
return rolePolicies, nil
}
if err = gjson.DecodeTo([]byte(value.String()), &rolePolicies); err != nil {
return nil, err
}
return
}
func Verify(ctx context.Context, roleKey, path, method string) (bool, error) {
rolePolicies, err := cachedPermissionPolicies(ctx)
if err != nil {
return false, err
}
for _, policy := range rolePolicies[roleKey] {
if !casbinutil.KeyMatch(path, policy.Perm) {
continue
}
ok, err := regexp.MatchString(policy.ActRegexp, method)
if err != nil {
return false, err
}
if ok {
return true, nil
}
}
return false, nil
}