fix: cache admin permissions in redis
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -53,8 +53,10 @@ func (s *sAdminMenu) Delete(ctx context.Context, in *adminin.MenuDeleteInp) (err
|
||||
if !exist.IsEmpty() {
|
||||
return gerror.New("请先删除该菜单下的所有菜单!")
|
||||
}
|
||||
_, err = dao.AdminMenu.Ctx(ctx).Where(dao.AdminMenu.Columns().Id, in.Id).Delete()
|
||||
return
|
||||
if _, err = dao.AdminMenu.Ctx(ctx).Where(dao.AdminMenu.Columns().Id, in.Id).Delete(); err != nil {
|
||||
return
|
||||
}
|
||||
return casbin.Refresh(ctx)
|
||||
}
|
||||
|
||||
// VerifyUnique 验证菜单唯一属性
|
||||
@@ -104,7 +106,7 @@ func (s *sAdminMenu) Edit(ctx context.Context, in *adminin.MenuEditInp) (err err
|
||||
return
|
||||
}
|
||||
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
if err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
in.Pid, in.Level, in.Tree, err = hgorm.AutoUpdateTree(ctx, &dao.AdminMenu, in.Id, in.Pid)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -121,8 +123,11 @@ func (s *sAdminMenu) Edit(ctx context.Context, in *adminin.MenuEditInp) (err err
|
||||
return err
|
||||
}
|
||||
}
|
||||
return casbin.Refresh(ctx)
|
||||
})
|
||||
return nil
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
return casbin.Refresh(ctx)
|
||||
}
|
||||
|
||||
// List 获取菜单列表
|
||||
|
||||
@@ -82,9 +82,9 @@ func (s *sAdminRole) Verify(ctx context.Context, path, method string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
ok, err := casbin.Enforcer.Enforce(user.RoleKey, path, method)
|
||||
ok, err := casbin.Verify(ctx, user.RoleKey, path, method)
|
||||
if err != nil {
|
||||
g.Log().Infof(ctx, "admin Verify Enforce err:%+v", err)
|
||||
g.Log().Infof(ctx, "admin Verify cache err:%+v", err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
@@ -221,7 +221,10 @@ func (s *sAdminRole) Edit(ctx context.Context, in *adminin.RoleEditInp) (err err
|
||||
// 如果当前角色有子级,更新子级tree关系树
|
||||
return updateRoleChildrenTree(ctx, in.Id, in.Level, in.Tree)
|
||||
})
|
||||
return
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return casbin.Refresh(ctx)
|
||||
}
|
||||
|
||||
// 新增
|
||||
@@ -229,7 +232,7 @@ func (s *sAdminRole) Edit(ctx context.Context, in *adminin.RoleEditInp) (err err
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return
|
||||
}
|
||||
return
|
||||
return casbin.Refresh(ctx)
|
||||
}
|
||||
|
||||
func updateRoleChildrenTree(ctx context.Context, _id int64, _level int, _tree string) (err error) {
|
||||
@@ -288,8 +291,9 @@ func (s *sAdminRole) Delete(ctx context.Context, in *adminin.RoleDeleteInp) (err
|
||||
|
||||
if _, err = dao.AdminRole.Ctx(ctx).Where("id", in.Id).Delete(); err != nil {
|
||||
err = gerror.Wrap(err, consts.ErrorORM)
|
||||
return
|
||||
}
|
||||
return
|
||||
return casbin.Refresh(ctx)
|
||||
}
|
||||
|
||||
func (s *sAdminRole) DataScopeSelect() (res form.Selects) {
|
||||
|
||||
Reference in New Issue
Block a user