springboot+vue+shiro功能权限
一、数据库表设计1.权限相关表CREATE TABLE `t_sys_action` (`id` varchar(32) NOT NULL COMMENT '主键',`name` varchar(32) DEFAULT NULL COMMENT '操作名称',`code` varchar(32) DEFAULT NULL COMMENT '编码',PRIMARY ...
·
一、数据库表设计
1.权限相关表
CREATE TABLE `t_sys_action` (
`id` varchar(32) NOT NULL COMMENT '主键',
`name` varchar(32) DEFAULT NULL COMMENT '操作名称',
`code` varchar(32) DEFAULT NULL COMMENT '编码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_resource` (
`id` varchar(32) NOT NULL COMMENT '主键',
`name` varchar(64) DEFAULT NULL COMMENT '资源名称',
`code` varchar(64) DEFAULT NULL COMMENT '资源编码',
`level` int(11) DEFAULT NULL COMMENT '资源级别',
`parent_id` varchar(32) DEFAULT NULL COMMENT '父级id',
`rank` int(11) DEFAULT NULL COMMENT '排序',
`img` varchar(64) DEFAULT NULL COMMENT '资源图片',
`url` varchar(126) DEFAULT NULL COMMENT '路由',
`description` varchar(255) DEFAULT NULL COMMENT '描述',
`type` varchar(255) DEFAULT NULL COMMENT '类型',
`isleaf` int(1) DEFAULT NULL COMMENT '是否叶子节点 1 是',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_privilege` (
`id` varchar(32) NOT NULL COMMENT '主键',
`name` varchar(64) DEFAULT NULL COMMENT '权限名称',
`code` varchar(64) DEFAULT NULL COMMENT '编码',
`resource_id` varchar(32) DEFAULT NULL COMMENT '资源编号',
`action_id` varchar(32) DEFAULT NULL COMMENT '操作编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_role` (
`id` varchar(32) NOT NULL COMMENT '主键',
`name` varchar(32) DEFAULT NULL COMMENT '角色名称',
`code` varchar(32) DEFAULT NULL COMMENT '编码',
`rank` varchar(32) DEFAULT NULL COMMENT '排序',
`description` varchar(128) DEFAULT NULL COMMENT '描述',
`enabled` int(1) DEFAULT NULL COMMENT '状态 0 删除 1启用 2禁用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_role_privilege` (
`id` varchar(32) NOT NULL COMMENT '主键',
`role_id` varchar(32) DEFAULT NULL COMMENT '角色编号',
`privilege_id` varchar(32) DEFAULT NULL COMMENT '权限编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_sys_user` (
`id` varchar(32) NOT NULL COMMENT '主键',
`user_name` varchar(32) DEFAULT NULL COMMENT '姓名',
`password` varchar(32) DEFAULT NULL COMMENT '密码',
`nick_name` varchar(64) DEFAULT NULL,
`true_name` varchar(64) DEFAULT NULL COMMENT '真实姓名',
`salt` varchar(64) DEFAULT NULL COMMENT '盐',
`gender` int(11) DEFAULT NULL COMMENT '0 保密 1 男 2女',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`mobile` varchar(20) DEFAULT NULL COMMENT '电话号码',
`email` varchar(64) DEFAULT NULL COMMENT '邮箱',
`country` varchar(32) DEFAULT NULL COMMENT '国籍',
`province` varchar(32) DEFAULT NULL COMMENT '省',
`type` int(1) DEFAULT NULL COMMENT '1,厂家,2机构',
`city` varchar(126) DEFAULT NULL COMMENT '城市',
`avatar_url` varchar(256) DEFAULT NULL COMMENT '头像',
`language` varchar(64) DEFAULT NULL,
`last_login_ip` varchar(32) DEFAULT NULL,
`last_login_time` varchar(32) DEFAULT NULL,
`create_time` varchar(32) DEFAULT NULL,
`update_time` varchar(32) DEFAULT NULL,
`create_by` varchar(32) DEFAULT NULL,
`update_by` varchar(32) DEFAULT NULL,
`enabled` int(1) DEFAULT NULL COMMENT '状态 0 删除 1启用 2禁用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=' 用户表';
CREATE TABLE `t_sys_user_role` (
`id` varchar(32) NOT NULL COMMENT '主键',
`user_id` varchar(32) DEFAULT NULL COMMENT '用户编号',
`role_id` varchar(32) DEFAULT NULL COMMENT '角色编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
其他省略。。。
2. 相关视图
CREATE ALGORITHM = UNDEFINED DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v_privilege` AS SELECT
`t_sys_privilege`.`id` AS `id`,
`t_sys_privilege`.`resource_id` AS `resourceid`,
`t_sys_privilege`.`action_id` AS `actionid`,
`t_sys_resource`.`code` AS `resourcecode`,
`t_sys_resource`.`name` AS `resourcename`,
`t_sys_resource`.`type` AS `resourcetype`,
`t_sys_resource`.`parent_id` AS `parent_id`,
`t_sys_action`.`name` AS `actionname`,
concat(
`t_sys_resource`.`code`,
':',
`t_sys_action`.`code`
) AS `privilegecode`
FROM
(
(
`t_sys_resource`
LEFT JOIN `t_sys_privilege` ON (
(
`t_sys_privilege`.`resource_id` = `t_sys_resource`.`id`
)
)
)
LEFT JOIN `t_sys_action` ON (
(
`t_sys_privilege`.`action_id` = `t_sys_action`.`id`
)
)
)
CREATE ALGORITHM = UNDEFINED DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v_user_role` AS SELECT DISTINCT
`usr`.`id` AS `id`,
`usrr`.`user_id` AS `userid`,
`usrr`.`role_id` AS `roleid`,
`usr`.`user_name` AS `username`
FROM
(
`t_sys_user` `usr`
LEFT JOIN `t_sys_user_role` `usrr` ON (
(
`usrr`.`user_id` = `usr`.`id`
)
)
)
WHERE
(`usrr`.`role_id` IS NOT NULL)
CREATE ALGORITHM = UNDEFINED DEFINER = `root`@`%` SQL SECURITY DEFINER VIEW `v_user_privilege` AS SELECT
`rl`.`userid` AS `USERID`,
`rl`.`username` AS `USERNAME`,
`rl`.`roleid` AS `ROLEID`,
`url`.`name` AS `ROLENAME`,
`privilge`.`id` AS `PRIVILEGEID`,
`sr`.`id` AS `RESOURCEID`,
`sr`.`code` AS `RESOURCECODE`,
`sr`.`name` AS `RESOURCENAME`,
`sr`.`type` AS `RESOURCETYPE`,
`sr`.`parent_id` AS `PARENTID`,
`sa`.`id` AS `ACTIONID`,
`sa`.`code` AS `ACTIONCODE`,
`sa`.`name` AS `ACTIONNAME`,
concat(
`sr`.`code`,
':',
`sa`.`code`
) AS `PRIVILEGECODE`
FROM
(
(
(
(
(
`v_user_role` `rl`
LEFT JOIN `t_sys_role` `url` ON ((`rl`.`roleid` = `url`.`id`))
)
LEFT JOIN `t_sys_role_privilege` `urp` ON (
(`url`.`id` = `urp`.`role_id`)
)
)
LEFT JOIN `t_sys_privilege` `privilge` ON (
(
`urp`.`privilege_id` = `privilge`.`id`
)
)
)
LEFT JOIN `t_sys_resource` `sr` ON (
(
`privilge`.`resource_id` = `sr`.`id`
)
)
)
LEFT JOIN `t_sys_action` `sa` ON (
(
`privilge`.`action_id` = `sa`.`id`
)
)
)
二、菜单栏,根据用户权限查询
1.查询与用户相关的权限资源(最底层的子节点,权限直接挂载在功能点上)
<select id="getResourceByUserName" resultMap="BaseResultMap">
SELECT
*
FROM
t_sys_resource
WHERE
id IN (
SELECT DISTINCT
RESOURCEID
FROM
`v_user_privilege`
WHERE
USERName = #{userName, jdbcType=VARCHAR}
)
</select>
2.根据子节点递归查找所有父节点,组装成树结构
service层:
/**
* 根据用户名称获取与权限相关的所有资源(父子级)
*
* @return
*/
public ServiceResult<List<ResourceAO>> getResource(String userName) {
//1.查询所有资源
ServiceResult<List<ResourceAO>> listServiceResult = selectByCriteria(null);
List<ResourceAO> allResourceList = null;
if (listServiceResult != null && listServiceResult.isSucceed() && !CollectionUtils.isEmpty(listServiceResult.getData())) {
allResourceList = listServiceResult.getData();
}
//超级管理员
if(Constant.SYSTEM_SUPER_ADMIN.equals(userName)){
return listTreeNodes(allResourceList);
}
//2.查询用户权限关联的资源
List<ResourceAO> resourceChildren = getResourceByUserName(userName);
//3.根据权限关联的资源(子级)查询所有父级
List<ResourceAO> parentResourceList = new ArrayList<>();
if (!CollectionUtils.isEmpty(resourceChildren)) {
for (ResourceAO child : resourceChildren) {
getParentResourceList(allResourceList, child.getId(), parentResourceList);
}
}
//查询到的资源组装成树节点
return listTreeNodes(parentResourceList);
}
/**
* 根据子级查询所有父级资源
*
* @param allResourceList
* @param childId
* @param parentResourceList
* @return
*/
private List<ResourceAO> getParentResourceList(List<ResourceAO> allResourceList, String childId, List<ResourceAO> parentResourceList) {
if (!CollectionUtils.isEmpty(allResourceList)) {
for (ResourceAO resource : allResourceList) {
// 判断是否存在父节点
if (resource.getId().equals(childId)) {
// 递归遍历上一级
getParentResourceList(allResourceList, resource.getParentId(), parentResourceList);
if (!parentResourceList.contains(resource)) {
parentResourceList.add(resource);
}
}
}
return parentResourceList;
}
return null;
}
/**
* 获取树结构数据
*
* @return
*/
public ServiceResult<List<ResourceAO>> listTreeNodes(List<ResourceAO> allList) {
ServiceResult<List<ResourceAO>> ret = new ServiceResult<>();
List<ResourceAO> parentList = new ArrayList<>();//根节点
List<ResourceAO> allResourceList = null;
if (!CollectionUtils.isEmpty(allList)) {
allResourceList = allList;
for (ResourceAO resource : allList) {
if (StringUtils.isEmpty(resource.getParentId())) {
parentList.add(resource);
}
}
}
//返回的树形节点数据
List<ResourceAO> treeNodeList = new ArrayList<>();
if (!CollectionUtils.isEmpty(parentList)) {
for (ResourceAO parent : parentList) {
//递归查询所有子节点
treeNodeList.add(recursiveTree(parent, allResourceList));
}
}
ret.setData(treeNodeList);
ret.setSucceed(true);
return ret;
}
/**
* 递归算法解析成树形结构
*/
public ResourceAO recursiveTree(ResourceAO parentNode, List<ResourceAO> allResourceList) {
List<ResourceAO> childTreeNodes = getChildTree(parentNode.getId(), allResourceList);
if (!CollectionUtils.isEmpty(childTreeNodes)) {
for (ResourceAO child : childTreeNodes) {
ResourceAO n = recursiveTree(child, allResourceList);
parentNode.getChildren().add(n);
}
}
return parentNode;
}
/**
* 根据父节点ID获取所有子节点
*/
public List<ResourceAO> getChildTree(String parentId, List<ResourceAO> allResourceList) {
List<ResourceAO> childNodes = new ArrayList<>();
if (!CollectionUtils.isEmpty(allResourceList)) {
for (ResourceAO resource : allResourceList) {
if (parentId.equals(resource.getParentId())) {
childNodes.add(resource);
}
}
}
return childNodes;
}
controller层:
/**
* 获取资源.
*
* @return
*/
@RequestMapping(value = "/getResource", method = {RequestMethod.GET, RequestMethod.POST})
@LogOperation(action = "获取资源")
public Object getResource(@RequestParam String userName) {
return resourceService.getResource(userName);
}
此时就完成了首页菜单根据权限进行树结构后端接口的组装。
3.vue前端从后端接口获取菜单树并在页面展示
(1)MenuTree.vue 菜单树组件
<template>
<el-submenu v-if="menu.children && menu.children.length >= 1" :key="menu.id" :index="menu.name">
<template slot="title">
<i :class="menu.img" :style="{ marginLeft: asideContainerW }"></i>
<span slot="title">{{menu.name}}</span>
</template>
<MenuTree v-for="item in menu.children" :menu="item" :key="item.id"></MenuTree>
</el-submenu>
<el-menu-item v-else :index="menu.url" :key="menu.id" @click="handleRoute(menu)">
<i :class="menu.img" :style="{ marginLeft: asideContainerChildW }"></i>
<span slot="title" style="font-size: 12px">{{menu.name}}</span>
</el-menu-item>
</template>
<script>
export default {
name: 'MenuTree',
data() {
return {
asideContainerW: '2rem',
asideContainerChildW: '4rem'
}
},
props: {
menu: {
type: Object,
required: true
}
},
methods: {
handleRoute(menu) {
// 通过菜单URL跳转至指定路由
this.$router.push(menu.url)
}
}
}
</script>
(2)vuex和axios结合查询权限菜单数据:
(3)取出上面后台查出的菜单数据并展示:
三、角色授权
1.资源权限树结构的拼装:
(1) 权限和资源表整合成总的资源
<select id="getResourceWithPrivilege" resultMap="BaseResultMap">
select id,name,code,parent_id from t_sys_resource
UNION all
SELECT
privilege.id AS id,
action.name AS name,
concat(resource.code,':',action.code) AS code,
resource.id as parent_id
FROM
t_sys_resource resource
LEFT JOIN t_sys_privilege privilege ON privilege.resource_id = resource.id
LEFT JOIN t_sys_action action ON privilege.action_id = action.id
where privilege.id is not null
</select>
2. 获取资源权限树
service层:
/**
* 获取资源树
*
* @return
*/
public ServiceResult<List<ResourceAO>> getResourceTreeNode() {
//查询所有资源
List<ResourceAO> allResource = getResourceWithPrivilege();
return listTreeNodes(allResource);
}
/**
* 权限和资源表整合成总的资源
*
* @return
*/
@Override
public List<ResourceAO> getResourceWithPrivilege() {
return resourceCustomizedMapper.getResourceWithPrivilege();
}
这里的listTreeNodes方法上边已经列出过。
controller层:
/**
* 获取资源树结构.
*
* @return
*/
@RequestMapping(value = "/getResourceTreeNode", method = {RequestMethod.GET, RequestMethod.POST})
@LogOperation(action = "获取资源树结构")
public Object getResourceTreeNode() {
return resourceService.getResourceTreeNode();
}
3.vue前端:
<template v-if="privilegeShow">
<el-dialog title="角色授权功能菜单" :visible.sync="privilegeShow" width="40%">
<el-form :model="privilegeForm" :inline="true" ref="form" class="demo-form-inline"
style="margin-bottom: 5px;text-align: center;margin-top: 0px">
<el-form-item label="角色名称:" required prop="name">
<el-input v-model="privilegeForm.name" disabled="disabled"></el-input>
</el-form-item>
<el-form-item label="角色编码:">
<el-input v-model="privilegeForm.code" disabled="disabled"></el-input>
</el-form-item>
</el-form>
<el-tag size="small">授权功能菜单</el-tag>
<el-divider></el-divider>
<template>
<el-row>
<el-col :span="2" :offset="20">
<div class="grid-content bg-purple-dark">
<el-checkbox v-model="checked" @change="checkedAll">全选</el-checkbox>
</div>
</el-col>
</el-row>
</template>
<ul class="infinite-list" style="height:350px;overflow:auto">
<el-tree
:data="resourceTree"
show-checkbox
node-key="id"
ref="privilegeTree"
default-expand-all
:default-checked-keys="rolePrivilegeData"
:props="defaultProps" style="margin-left: 10px;">
</el-tree>
</ul>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="privilegeShow = false">取消</el-button>
<el-button size="mini" type="primary" @click="submitPrivilege" :loading="editLoading">确定</el-button>
</div>
</el-dialog>
</template>
computed: {
...mapState('role', [
'dataSource',
'loading',
'editLoading',
'resourceTree',
'rolePrivilegeData'
]),
}
四、权限控制按钮的隐藏和显示
permission.js:
import Vue from 'vue'
/**权限指令**/
Vue.directive('has', {
inserted: function (el, binding) {
if (!Vue.prototype.$_has(binding.value)) {
el.parentNode.removeChild(el);
}
}
});
//权限检查方法
Vue.prototype.$_has = function (value) {
let isExist = false;
let user = localStorage.getItem("user");
if ("admin" == user) {
return true;
}
let premissionsStr = localStorage.getItem("permissions");
if (premissionsStr == undefined || premissionsStr == null) {
return false;
}
if (premissionsStr.indexOf(value) > -1) {
isExist = true;
}
return isExist;
};
main.js中引入:
import has from './public/permission.js';
页面:
<el-button size="mini" @click="addDialog" type="primary" v-has="'roleManage:manage'">新增</el-button>
更多推荐
已为社区贡献10条内容
所有评论(0)