一步步实现微服务权限管理系统(8)
前言
- 前端参考了很多框架,可谓百花齐放,但很多封装过剩,不利于学习和应用,最终我选择了 [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin)
- 后端我将使用 go-zero 来带领大家一步步实现一个权限管理系统
- 本系列项目存放在 purezeroadmin 中,每一部分我都将打tag,并保证每个tag能正常运行。请多点赞和评论。
- 后面示例均为
purezeroadmin
项目为例,你们可以根据需要自建工程来进行试验。均采用vscode
进行试验。 go-zero
常用命令我将放入其对应的makefile
文件中。
本节概述
- 路由数据持久化
- 路由数据组装
后端修改
新增 tb_router
表及相关数据
- 生成对应数据
/*!40101 SET NAMES utf8mb4 */;
/*!40101 SET SQL_MODE=''*/;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`purezeroadmin` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
USE `purezeroadmin`;
/*Table structure for table `tb_router` */
CREATE TABLE `tb_router` (
`id` bigint NOT NULL AUTO_INCREMENT,
`parent_id` bigint NOT NULL DEFAULT '0',
`path` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`component` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`meta_title` varchar(64) NOT NULL,
`meta_icon` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '',
`meta_rank` bigint NOT NULL DEFAULT '0',
`meta_roles` json DEFAULT NULL,
`meta_auths` json DEFAULT NULL,
`create_ts` bigint NOT NULL DEFAULT '0',
`update_ts` bigint NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
/*Data for the table `tb_router` */
insert into `tb_router`(`id`,`parent_id`,`path`,`name`,`component`,`meta_title`,`meta_icon`,`meta_rank`,`meta_roles`,`meta_auths`,`create_ts`,`update_ts`) values (1,0,'/permission','','','权限管理','ep:lollipop',10,NULL,NULL,0,0);
insert into `tb_router`(`id`,`parent_id`,`path`,`name`,`component`,`meta_title`,`meta_icon`,`meta_rank`,`meta_roles`,`meta_auths`,`create_ts`,`update_ts`) values (2,1,'/permission/page/index','PermissionPage','','页面权限','',0,'[\"admin\"]',NULL,0,0);
insert into `tb_router`(`id`,`parent_id`,`path`,`name`,`component`,`meta_title`,`meta_icon`,`meta_rank`,`meta_roles`,`meta_auths`,`create_ts`,`update_ts`) values (3,1,'/permission/button','','','按钮权限','',0,'[\"admin\", \"common\"]',NULL,0,0);
insert into `tb_router`(`id`,`parent_id`,`path`,`name`,`component`,`meta_title`,`meta_icon`,`meta_rank`,`meta_roles`,`meta_auths`,`create_ts`,`update_ts`) values (4,3,'/permission/button/router','PermissionButtonRouter','permission/button/index','路由返回按钮权限','',0,NULL,'[\"permission:btn:add\", \"permission:btn:edit\", \"permission:btn:delete\"]',0,0);
insert into `tb_router`(`id`,`parent_id`,`path`,`name`,`component`,`meta_title`,`meta_icon`,`meta_rank`,`meta_roles`,`meta_auths`,`create_ts`,`update_ts`) values (5,3,'/permission/button/login','PermissionButtonLogin','permission/button/perms','登录接口返回按钮权限','',0,NULL,NULL,0,0);
- 生成
models
goctl model mysql datasource --url "root:123456@tcp(127.0.0.1:55506)/purezeroadmin" -t="*" --dir user-api/models --home template
- 配置
muser-api/internal/svc/servicecontext.go
type ServiceContext struct {
Config config.Config
TbUserModel models.TbUserModel
TbRoleModel models.TbRoleModel
TbRouterModel models.TbRouterModel
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := sqlx.NewMysql(c.Dsn)
return &ServiceContext{
Config: c,
TbUserModel: models.NewTbUserModel(conn),
TbRoleModel: models.NewTbRoleModel(conn),
TbRouterModel: models.NewTbRouterModel(conn),
}
}
user-api/models/tbroutermodel.go
增加函数
...
TbRouterModel interface {
tbRouterModel
withSession(session sqlx.Session) TbRouterModel
FindAllFromParentID(ctx context.Context, parentID int64) ([]*TbRouter, error)
}
...
func (m *customTbRouterModel) FindAllFromParentID(ctx context.Context, parentID int64) ([]*TbRouter, error) {
var resp []*TbRouter
err := m.conn.QueryRowsCtx(ctx, &resp, "select * from tb_router where parent_id = ?", parentID)
return resp, err
}
user-api/api/user.api
中 RouterData
返回修改为指针形式
type RouterData {
Path string `json:"path"`
Name string `json:"name,omitempty"`
Component string `json:"component,omitempty"`
Meta Meta `json:"meta"`
Children []*RouterData `json:"children,omitempty"`
}
...
@server (
jwt: Auth // 开启 jwt 认证
)
service user-api {
@doc "获取路由"
@handler userRouter
get /api/get-async-routes (UserRouterReq) returns ([]*RouterData)
}
user-api/internal/logic/userrouterlogic.go
主要生成逻辑
func (l *UserRouterLogic) UserRouter(req *types.UserRouterReq) (resp []*types.RouterData, err error) {
userID, err := helper.GetUserIDFromContext(l.ctx)
if err != nil {
return nil, err
}
tbUser, err := l.svcCtx.TbUserModel.FindOne(l.ctx, userID)
if err != nil {
return nil, err
}
roles, permissions, err := helper.GetAuths(l.ctx, l.svcCtx, tbUser)
if err != nil {
return nil, err
}
isAdmin := arrutil.Contains(roles, "admin")
return l.GetRecursionRoutersByParentID(0, isAdmin, roles, permissions)
}
func (l *UserRouterLogic) GetRouterByID(id int64, isAdmin bool, roles, permissions []string) (routerData *types.RouterData, err error) {
router, err := l.svcCtx.TbRouterModel.FindOne(l.ctx, id)
if err != nil {
return nil, err
}
return helper.RouterToData(router, isAdmin, roles, permissions)
}
func (l *UserLoginLogic) GetRoutersByParentID(parentID int64, isAdmin bool, roles, permissions []string) (routerDatas []*types.RouterData, err error) {
routers, err := l.svcCtx.TbRouterModel.FindAllFromParentID(l.ctx, parentID)
if err != nil {
return nil, err
}
for _, v := range routers {
routerData, err := helper.RouterToData(v, isAdmin, roles, permissions)
if err != nil {
return nil, err
}
routerDatas = append(routerDatas, routerData)
}
return routerDatas, nil
}
func (l *UserRouterLogic) UpdateRouterData(routerData *types.RouterData, id int64, isAdmin bool, roles, permissions []string) (err error) {
routers, err := l.svcCtx.TbRouterModel.FindAllFromParentID(l.ctx, id)
if err != nil {
return err
}
for _, v := range routers {
child, err := l.GetRecursionRouterByID(v.Id, isAdmin, roles, permissions)
if err != nil {
return err
}
if child == nil {
continue
}
routerData.Children = append(routerData.Children, child)
}
return nil
}
func (l *UserRouterLogic) GetRecursionRouterByID(id int64, isAdmin bool, roles, permissions []string) (routerData *types.RouterData, err error) {
routerData, err = l.GetRouterByID(id, isAdmin, roles, permissions)
if err != nil {
return nil, err
}
err = l.UpdateRouterData(routerData, id, isAdmin, roles, permissions)
return routerData, err
}
func (l *UserRouterLogic) GetRecursionRoutersByParentID(parentID int64, isAdmin bool, roles, permissions []string) (routerDatas []*types.RouterData, err error) {
routers, err := l.svcCtx.TbRouterModel.FindAllFromParentID(l.ctx, parentID)
if err != nil {
return nil, err
}
for _, v := range routers {
routerData, err := helper.RouterToData(v, isAdmin, roles, permissions)
if err != nil {
return nil, err
}
err = l.UpdateRouterData(routerData, v.Id, isAdmin, roles, permissions)
if err != nil {
return nil, err
}
routerDatas = append(routerDatas, routerData)
}
return routerDatas, nil
}
测试
- 登陆不同用户可观察到菜单变化
tag版本
purezeroadmin
项目下
git checkout v1.7.0
接下来
casbin的引入