Skip to content

一步步实现微服务权限管理系统(9)

前言

  • 前端参考了很多框架,可谓百花齐放,但很多封装过剩,不利于学习和应用,最终我选择了 [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin)
  • 后端我将使用 go-zero 来带领大家一步步实现一个权限管理系统
  • 本系列项目存放在 purezeroadmin 中,每一部分我都将打tag,并保证每个tag能正常运行。请多点赞和评论。
  • 后面示例均为 purezeroadmin 项目为例,你们可以根据需要自建工程来进行试验。均采用vscode进行试验。
  • go-zero 常用命令我将放入其对应的 makefile 文件中。

本节概述

  • casbin 是一个非常流行的访问控制模型,用来RBAC权限控制非常方便, 参考 https://casbin.org/zh/docs/rbac
  • 先将路由所对应的权限映射为casbin的文件测试
  • 之前生成路由树的逻辑中权限判断可以交给 casbin 来做了

后端修改

测试 casbin

  • 创建 casbin.conf
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act || r.sub == "admin"
  • 创建 casbin.csv
p, 1, permission:btn:add, get
p, 2, permission:btn:edit, get
p, 3, permission:btn:delete, get

p, 1000000, /permission, get
p, 1010000, /permission/page/index, get
p, 1020000, /permission/button, get
p, 1020100, /permission/button/router, get
p, 1020200, /permission/button/login, get

g, 1, 1020100
g, 2, 1020100
g, 3, 1020100

g, common,  1000000
g, common,  1020000
g, common,  1
g, common,  2
g, common,  1020200
  • 测试请求
common, /permission, get
common, /permission/page/index, get
common, /permission/button, get
common, /permission/button/router, get
common, /permission/button/login, get
common, permission:btn:add, get
common, permission:btn:edit, get
common, permission:btn:delete, get

admin, /permission, get
admin, /permission/page/index, get
admin, /permission/button, get
admin, /permission/button/router, get
admin, /permission/button/login, get
admin, permission:btn:add, get
admin, permission:btn:edit, get
admin, permission:btn:delete, get
  • 执行结果
true Reason: ["1000000","/permission","get"]
false
true Reason: ["1020000","/permission/button","get"]
true Reason: ["1020100","/permission/button/router","get"]
true Reason: ["1020200","/permission/button/login","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["2","permission:btn:edit","get"]
false
// ignore
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
true Reason: ["1","permission:btn:add","get"]
// ignore

可根据上述文件在 https://casbin.org/zh/editor 进行测试

permission:btn:add 这些是为了查看调用所以映射了subject

casbin 引入到后端

  • 配置信息修改

user-api/etc/user-api.yaml

# casbin
Casbin:
  ModelFile: "casbin.conf"
  PolicyFile: "casbin.csv"

user-api/internal/config/config.go

type Config struct {
    ...
    Casbin struct {
        ModelFile  string
        PolicyFile string
    }
}
  • 修改服务上下文user-api/internal/svc/servicecontext.go
type ServiceContext struct {
    Config        config.Config
    TbUserModel   models.TbUserModel
    TbRoleModel   models.TbRoleModel
    TbRouterModel models.TbRouterModel
    Enforcer      *casbin.SyncedEnforcer
}

func NewServiceContext(c config.Config) *ServiceContext {
    conn := sqlx.NewMysql(c.Dsn)
    enforcer, err := casbin.NewSyncedEnforcer(c.Casbin.ModelFile, c.Casbin.PolicyFile)
    if err != nil {
        logx.Errorf("Error on NewSyncedEnforcer: %+v", err)
        return nil
    }
    return &ServiceContext{
        Config:        c,
        TbUserModel:   models.NewTbUserModel(conn),
        TbRoleModel:   models.NewTbRoleModel(conn),
        TbRouterModel: models.NewTbRouterModel(conn),
        Enforcer:      enforcer,
    }
}
  • user-api/helper/helper.go 判断逻辑改成casbin来判断
func RouterToData(svcCtx *svc.ServiceContext, router *models.TbRouter, isAdmin bool, roles, permissions []string) (routerData *types.RouterData, err error) {
    routerData = &types.RouterData{
        Path:      router.Path,
        Name:      router.Name,
        Component: router.Component,
        Meta: types.Meta{
            Title: router.MetaTitle,
            Icon:  router.MetaIcon,
            Rank:  router.MetaRank,
        },
    }

    pass := false
    for _, role := range roles {
        getPass, _ := svcCtx.Enforcer.Enforce(role, routerData.Path, "get")
        if getPass {
            pass = true
        }
    }
    for _, permission := range permissions {
        getPass, _ := svcCtx.Enforcer.Enforce(permission, routerData.Path, "get")
        if getPass {
            pass = true
        }
    }

    if !pass {
        return nil, nil
    }

    if router.MetaRoles.Valid {
        routerData.Meta.Roles, err = jsonutil.ToArray[string](router.MetaRoles.String)
        if err != nil {
            return nil, err
        }
    }

    if router.MetaAuths.Valid {
        routerData.Meta.Auths, err = jsonutil.ToArray[string](router.MetaAuths.String)
        if err != nil {
            return nil, err
        }
    }

    return routerData, nil
}

测试

  • 前后端测试,通过

tag版本

purezeroadmin 项目下

git checkout v1.8.0

接下来

casbin 规则持久化

Comments