The code is too ugly, so it is not recommended to copy it. You can take a look at the implementation idea of RBAC, which is universal.
git clone https://github.com/wjkang/d2-admin-pm.git
npm install
npm start
Requires support from backend mock service
git clone https://github.com/wjkang/d2-admin-server.git
npm install
npm start
The created
content in main.js
is transferred to router/index.js
, and relevant logic is added.
Modified axios- related code plugin/axios/index.js
to support interface-level permission control and support configuration of loading effects.
Add the menu module to the vuex store and add fullAside , the full path is store.state.d2admin.menu.fullAside
Add the permission module to the vuex store to store the user's function permission code, role code, interface with access permissions and whether the administrator ID is
export default {
namespaced : true ,
state : {
//功能编码
functions : [ ] ,
//角色编码
roles : [ ] ,
//接口
interfaces : {
GET : [ ] ,
POST : [ ] ,
PUT : [ ] ,
DELETE : [ ]
} ,
//是否管理员
isAdmin : false
} ,
mutations : {
set ( state , data ) {
state . functions = data . functions ;
state . roles = data . roles ;
state . isAdmin = data . isAdmin ;
state . interfaces = data . interfaces ;
}
}
}
This part of load
action of the account
module in the vuex store:
// DB -> store 持久化数据加载上次退出时的多页列表
await dispatch ( 'd2admin/page/openedLoad' , null , { root : true } )
Go to router/index.js
, it needs to be executed after loading the permission route.
菜单
and功能
. There can be multiple functions under a menu. The permission
field of菜单
type identifies the function permissions required to access this menu. The permission
field of功能
type is equivalent to the alias of this function, so菜单
type The permission
field is permission
value of a child node of a功能
type.permission
field. Using the original login logic of d2admin
, the global routing guard determines whether the permission information has been pulled, and marks it as obtained after it is obtained.
The permission information that the backend needs to return includes the role code set after permission filtering, the function code set, the interface information set, the menu list, the routing list, and whether the system administrator is identified. The format is as follows
{
"statusCode" : 200 ,
"msg" : "" ,
"data" : {
"userName" : "MenuManager" ,
"userRoles" : [
"R_MENUADMIN"
] ,
"userPermissions" : [
"p_menu_view" ,
"p_menu_edit" ,
"p_menu_menu"
] ,
"accessMenus" : [
{
"title" : "系统" ,
"path" : "/system" ,
"icon" : "cogs" ,
"children" : [
{
"title" : "系统设置" ,
"icon" : "cogs" ,
"children" : [
{
"title" : "菜单管理" ,
"path" : "/system/menu" ,
"icon" : "th-list"
}
]
} ,
{
"title" : "组织架构" ,
"icon" : "pie-chart" ,
"children" : [
{
"title" : "部门管理" ,
"icon" : "html5"
} ,
{
"title" : "职位管理" ,
"icon" : "opencart"
}
]
}
]
}
] ,
"accessRoutes" : [
{
"name" : "System" ,
"path" : "/system" ,
"component" : "layoutHeaderAside" ,
"componentPath" : "layout/header-aside/layout" ,
"meta" : {
"title" : "系统设置" ,
"cache" : true
} ,
"children" : [
{
"name" : "MenuPage" ,
"path" : "/system/menu" ,
"component" : "menu" ,
"componentPath" : "pages/sys/menu/index" ,
"meta" : {
"title" : "菜单管理" ,
"cache" : true
}
} ,
{
"name" : "RoutePage" ,
"path" : "/system/route" ,
"component" : "route" ,
"componentPath" : "pages/sys/route/index" ,
"meta" : {
"title" : "路由管理" ,
"cache" : true
}
} ,
{
"name" : "RolePage" ,
"path" : "/system/role" ,
"component" : "role" ,
"componentPath" : "pages/sys/role/index" ,
"meta" : {
"title" : "角色管理" ,
"cache" : true
}
} ,
{
"name" : "UserPage" ,
"path" : "/system/user" ,
"component" : "user" ,
"componentPath" : "pages/sys/user/index" ,
"meta" : {
"title" : "用户管理" ,
"cache" : true
}
} ,
{
"name" : "InterfacePage" ,
"path" : "/system/interface" ,
"component" : "interface" ,
"meta" : {
"title" : "接口管理"
}
}
]
}
] ,
"accessInterfaces" : [
{
"path" : "/menu/:id" ,
"method" : "get"
} ,
{
"path" : "/menu" ,
"method" : "get"
} ,
{
"path" : "/menu/save" ,
"method" : "post"
} ,
{
"path" : "/interface/paged" ,
"method" : "get"
}
] ,
"isAdmin" : 0 ,
"avatarUrl" : "https://api.adorable.io/avatars/85/[email protected]"
}
}
Merge the fixed menu ( /menu/header
, /menu/aside
) with the permission menu ( accessMenus
) returned by the backend, and store it in the corresponding vuex store module
...
let allMenuAside = [ ... menuAside , ... permissionMenu ]
let allMenuHeader = [ ... menuHeader , ... permissionMenu ]
. . .
// 设置顶栏菜单
store . commit ( 'd2admin/menu/headerSet' , allMenuHeader )
// 设置侧边栏菜单
store . commit ( 'd2admin/menu/fullAsideSet' , allMenuAside )
// 初始化菜单搜索功能
store . commit ( 'd2admin/search/init' , allMenuHeader )
By default, routerMapComponents
is used to process permission routes returned by the backend.
//处理动态添加的路由
const formatRoutes = function ( routes ) {
routes . forEach ( route => {
route . component = routerMapComponents [ route . component ]
if ( route . children ) {
formatRoutes ( route . children )
}
} )
}
. . .
formatRoutes ( permissionRouter )
//动态添加路由
router . addRoutes ( permissionRouter ) ;
// 处理路由 得到每一级的路由设置
store . commit ( 'd2admin/page/init' , [ ... frameInRoutes , ... permissionRouter ] )
For routing processing methods and differences, please see the related articles later.
Store the role coding set, function coding set, interface information set, and whether the system administrator ID is stored in the corresponding vuex store module
...
permission . functions = userPermissionInfo . userPermissions
permission . roles = userPermissionInfo . userRoles
permission . interfaces = util . formatInterfaces ( userPermissionInfo . accessInterfaces )
permission . isAdmin = userPermissionInfo . isAdmin == 1
. . .
// 设置权限信息
store . commit ( 'd2admin/permission/set' , permission )
Supports control using role coding, function coding and interface permissions, as follows
export function getMenuList ( ) {
return request ( {
url : '/menu' ,
method : 'get' ,
interfaceCheck : true ,
permission : [ "p_menu_view" ] ,
loading : {
type : 'loading' ,
options : {
fullscreen : true ,
lock : true ,
text : '加载中...' ,
spinner : 'el-icon-loading' ,
background : 'rgba(0, 0, 0, 0.8)'
}
} ,
success : {
type : 'message' ,
options : {
message : '加载菜单成功' ,
type : 'success'
}
}
} )
}
interfaceCheck: true
means using interface permissions for control. If the interface information stored in the vuex store matches the interface currently being requested, the request can be initiated, otherwise the request will be intercepted.
permission:["p_menu_view"]
means using role coding and function coding for permission verification. If the role coding or function coding stored in the vuex store matches the currently represented coding, a request can be initiated, otherwise the request will be intercepted.
The source code is located in libs/permission.js
and can be modified according to your own needs.
The source code related to loading
configuration is in libs/loading.js
. You can configure it according to your own needs. The same is true for success
. The source code is in libs/loading.js
. Following this idea, you can configure other functions yourself, such as request failure, etc.
Use the directive v-permission
:
< el-button
v-permission:function.all =" ['p_menu_edit'] "
type =" primary "
icon =" el-icon-edit "
size =" mini "
@click =" batchEdit "
>批量编辑</ el-button >
The parameter can be function
or role
, indicating that function coding or role coding is used for verification. If it is empty, both are used for verification.
The modifier all
means that all codes in the instruction value must be matched.
The source code is located in plugin/permission/index.js
and can be modified according to your actual needs.
Use v-if
+ global method:
< el-button
v-if =" canAdd "
type =" primary "
icon =" el-icon-circle-plus-outline "
size =" mini "
@click =" add "
>添加</ el-button >
data ( ) {
return {
canAdd : this . hasPermissions ( [ "p_menu_edit" ] )
} ;
} ,
By default, both role coding and function coding are used for verification, and only one of them matches.
Similar methods also include hasFunctions
and hasRoles
.
The source code is located in plugin/permission/index.js
and can be modified according to your actual needs.
Do not use
v-if="hasPermissions(['p_menu_edit'])"
, which will cause the method to be executed multiple times
You can also directly read permission information from the vuex store in the component for verification.
Page-level components are placed in the pages/
directory and exported in the form of key-value in routerMapCompnonents/index.js
Fixed menus that do not require permission control are placed in menu/aside.js
and menu/header.js
Routes that do not require permission control are placed in router/routes.js
frameIn
Menus and routes that require permission control are added through the management function of the interface. Make sure that path
of the menu corresponds to path
of the route. Only when name
of the route is consistent with name
of the page component can keep-alive
take effect. component
of the route is in routerMapCompnonents/index.js
It can be matched by key in routerMapCompnonents/index.js
.
The addition of menus and routes during the development phase can be maintained by developers themselves and a list can be maintained. After going online, the list can be handed over to relevant people for maintenance.
If you find it troublesome and do not want menus and routes to be returned from the backend, you can maintain a menu and routes on the frontend (
component
in the routes still use strings, refer tomock/permissionMenuAndRouter.js
), and maintain the corresponding permissions on the menus and routes Coding, generally uses functional coding. The backend does not need to return menu and routing information, but other permission information, such as role coding, function coding, etc., is still needed. Through the function code list returned by the backend, the menus and routes that the user has permissions are filtered out on the frontend. The format of the filtered menus and routes is consistent with the format previously returned by the backend, and then the processed menus and routes are used as the backend. Just handle it the same as what is returned from the client.
Data mock uses d2-admin-server modified from lazy-mock. The data actually comes from the backend. Compared with other tools, it supports data persistence. It uses json files for storage and does not need to install a database. Simple configuration can automatically generate interfaces for addition, deletion, modification and query. For detailed usage, please see the lazy-mock documentation.
The backend uses middleware to control access permissions, such as:
. get ( '/menu' , PermissionCheck ( ) , controllers . menu . getMenuList )
PermissionCheck
uses the interface for verification by default to verify whether the APIs accessible to users match the current API. It supports the use of function coding and role coding for verification. PermissionCheck(["p_menu_edit"],["r_menu_admin"],true)
, Chapter One parameter is the function code, the second is the role code, and the third is whether to use the interface for verification.
Front-end code generation is still under development...
Summary of vue permission routing implementation method Summary of vue permission routing implementation method 2. Enterprise management system front-end and back-end separation architecture design series 1. Permission model