文章目录
效果图
Saas-Export项目的RBAC权限模型图
RABC权限模型的使用步骤
给用户授权的顺序
- 先给角色赋予权限
- 再将角色分配给用户
- 最后用户得到这些角色的所有权限
SaaS-Export角色授权
给角色添加权限,无非就是在中间表(角色模块表pe_role_module
)中生成记录。
对应关系(一对多):一个角色(role)对应多个模块(moudle)
1)给角色添加权限
2)给角色修改权限
3)给用户指定角色
4)给用户更新角色
给角色分配权限
1. 编写测试给角色分配权限的sql语句
-- 先创建一个角色
INSERT INTO pe_role (role_id,NAME)VALUES('ac9b2814-51bc-40db-8628-6cb20b77e5e9','test role_moudle')
-- 添加权限往中间表 pe_role_module(角色模块表) 添加用户权限(可以进入的模块) 参1:用户id 参2:模块id
INSERT INTO pe_role_module VALUES('ac9b2814-51bc-40db-8628-6cb20b77e5e9','201') -- 购销合同201
INSERT INTO pe_role_module VALUES('ac9b2814-51bc-40db-8628-6cb20b77e5e9','202') -- 出货表202
SELECT * FROM pe_role_module WHERE role_id='ac9b2814-51bc-40db-8628-6cb20b77e5e9'
-- 修改权限 (pe_role_module )先删除角色模块表的当前角色信息 参1:用户id 参2:模块id
DELETE FROM pe_role_module WHERE role_id='ac9b2814-51bc-40db-8628-6cb20b77e5e9'
INSERT INTO pe_role_module VALUES('ac9b2814-51bc-40db-8628-6cb20b77e5e9','201') -- 购销合同
INSERT INTO pe_role_module VALUES('ac9b2814-51bc-40db-8628-6cb20b77e5e9','202')-- 出货表
INSERT INTO pe_role_module VALUES('ac9b2814-51bc-40db-8628-6cb20b77e5e9','203')-- 合同管理
2. export_system_service子工程编写测试类测试角色授权
TestModuleService
//测试查找所有的模块
@Test
public void test05(){
List<Module> moduleList = iModuleService.findAllModules();
l.info("模块数量"+ moduleList.size() +"moduleList = "+moduleList);
}
//测试通过角色id查询角色的权限
@Test
public void test06(){
List<Module> myList = iModuleService.findModuleByRoleId("ac9b2814-51bc-40db-8628-6cb20b77e5e9");
l.info("模块数量: "+myList.size()+" \n角色的模块权限myList = "+myList);
}
//测试更新角色的权限(先删除、后更新)
@Test
public void test07(){
//修改一个角色的权限,不仅仅是添加,也可能是减少
String roleId="ac9b2814-51bc-40db-8628-6cb20b77e5e9";
//String moduleIds="201,202";//减少指定角色的权限
String moduleIds="201,202,203";//添加角色的权限
iModuleService.updateRoleModule(roleId,moduleIds);
}
3. export_system_service子工程的service接口和实现类
IModuleService
//查找所有模块
List<Module> findAllModules();
//通过角色查找从属于该角色的所有模块
List<Module> findModuleByRoleId(String roleId);
//通过角色id更新角色的模块信息(zTree树形,先删除该角色的所有模块权限,再添加)
void updateRoleModule(String roleId, String moduleIds);
ModuleServiceImpl
这里需要注意,再做更新角色权限(模块)的时候,先删除该角色的所有权限,然后进行更新,更新需要判断页面传来的参数是否有值(null或
""
空子字符串)如果是无值的,name就不进行saveRoleModule
保存角色权限,否则会抛出InvocationTargetException
异常。
也就是如果没有传过来模块参数就不需要进行保存,也就是情况角色的权限(更新的时候先删除了角色的所有权限)
@Override
public List<Module> findAllModules() {
return iModuleDao.findAll();
}
@Override
public List<Module> findModuleByRoleId(String roleId) {
return iModuleDao.findByRoleId(roleId);
}
//更新角色的模块信息
@Override
public void updateRoleModule(String roleId, String moduleIds) {
//先做删除,删除角色在中间表(角色模块表)中的记录
iModuleDao.deleteRoleModule(roleId);
// zTree获取所有的模块id,按,逗号分开 moduleIds 202,203
//判断该角色权限是否清空(该角色还有模块的情况,否则会抛出InvocationTargetException异常)
if(moduleIds!=null && moduleIds != ""){
String[] mids = moduleIds.split(",");
//更新角色模块
if (mids.length > 0) { //判断选择模块权限是否>0,再操作
//再作添加,将模块赋予给角色(角色模块表添加记录)
for (String mid : mids) {
iModuleDao.saveRoleModule(roleId, mid);
}
}
}else{
System.out.println("updateRoleModule 该用户没有任何权限了");
}
}
4. export_dao子工程写dao接口及其映射
IModuleDao
//通过角色id查询角色的模块权限
List<Module> findByRoleId(String roleId);
//删除指定角色的所有模块权限
void deleteRoleModule(String roleId);
//给角色添加模块(权限)
void saveRoleModule(String roleId, String mid);
IModuleDao.xml
<!-- 通过角色id查询角色的模块权限 -->
<select id="findByRoleId" parameterType="string" resultMap="moduleMap" >
select m.*
from pe_role_module rm
inner join ss_module m
on rm.module_id = m.module_id
where rm.role_id=#{roleId}
</select>
<!-- 删除指定角色的所有模块权限 -->
<delete id="deleteRoleModule" parameterType="string">
delete from pe_role_module where role_id=#{roleId}
</delete>
<!-- 给角色添加模块(权限) void saveRoleModule(String roleId, String mid);-->
<!-- 保存角色模块有两个参数,第一个参数是:角色id(roleId)第二个参数是:模块id(moduleId)
可以通过arg0、arg1...来接收
或者通过param1、param2...来接收
-->
<insert id="saveRoleModule">
insert into pe_role_module values(#{arg0},#{arg1})
</insert>
<!--
<insert id="saveRoleModule" >
insert into pe_role_module values(#{param1},#{param2})
</insert>
-->
5. export_web_manager子工程编写controller
RoleControllerController
// 去角色的模块表(需要角色的id,查找该角色的模块) location.href="${path}/system/role/toRoleModule?roleId="+id;
@RequestMapping(path="/toRoleModule",method ={ RequestMethod.GET, RequestMethod.POST})
public String toRoleModule(String roleId){//接收页面提交的roleId
//当前授权页面需要显示 角色名称
l.info("toRoleModule roleId=" + roleId);
//查找角色信息
Role role = iRoleService.findById(roleId);
//数据转发到页面
request.setAttribute("role",role);
return "system/role/role-module";
}
// 给role-module页面的zTree的树形角色模块菜单赋值(有权限的选中) $.get('${path}/role/getZtreeData?roleId=${role.roleId}',fn,'json')
@RequestMapping(path="/getZtreeData",method ={ RequestMethod.GET, RequestMethod.POST})
public @ResponseBody Object getZtreeData(String roleId) {//接收页面提交的roleId
//所有的权限(模块)查询出来
List<Module> all = iModuleService.findAllModules();
//根据roleId查询该角色的权限(有权限的模块打钩)
List<Module> myList = iModuleService.findModuleByRoleId(roleId);
//将list转换成 List<Map<String,Object>> { id:1, pId:0, name:"Sass管理", open:true},
List<Map<String,Object>> list = new ArrayList<>();
//返回给页面
for(Module m:all){
//生成一个集合 Map<String,Object> 表示一节点
Map<String,Object> node = new HashMap<String,Object>();
node.put("id",m.getModuleId());
node.put("pId",m.getParentId()); //菜单等级
node.put("name",m.getName());
node.put("open",true); //是否展开该菜单
//比较所有模块(权限)和当前角色拥有的模块是否相同
if(isInMyList(m,myList)){
node.put("checked",true);//当前角色拥有该权限,选中状态,有打勾就表示有这个权限,否则就是没有
}
//添加到集合中
list.add(node);
}
return list; //@ResponseBody将list转成json
}
//定义方法判断当前模块是否在该角色的模块列表用
//需要判断m是否在myList里面,如果在表示该角色有这个权限,否则没有
private boolean isInMyList(Module m, List<Module> myList) {
for(Module my:myList){
if(m.getModuleId().equals(my.getModuleId())){
l.info("isInMyList moduleId1 "+m.getModuleId()+" "+m.getName());
l.info("isInMyList moduleId2 "+my.getModuleId()+" "+my.getName());
return true;
}
}
return false;
}
//更新角色的模块(先全部删除,再根据选中的模块进行赋值到中间表角色模块表中) ${path}/system/role/updateRoleModule
@RequestMapping(path="/updateRoleModule",method ={ RequestMethod.GET, RequestMethod.POST})
public String updateRoleModule(String roleId,String moduleIds){//接收了页面提交的参数
l.info("updateRoleModule roleId="+roleId);
l.info("updateRoleModule moduleIds="+moduleIds);
//roleId=ac9b2814-51bc-40db-8628-6cb20b77e5e9
//更新角色的模块权限 moduleIds=202,203,204
iModuleService.updateRoleModule(roleId,moduleIds);
return "redirect:/system/role/toList";
}
6. export_web_manager子工程编写jsp页面
role-list
页面权限按钮
<button type="button" class="btn btn-default" title="权限" onclick="findModuleByRoleId()"><i class="fa fa-users"></i> 权限</button>
绑定js进行跳转
//查找选中角色的所有权限
function findModuleByRoleId(){
var roleId = getCheckId();
if(roleId) {
//去角色模块列表
location.href="${path}/system/role/toRoleModule?roleId="+roleId;
}else{
alert("请勾选待处理的记录,且每次只能勾选一个")
}
}
role-module.jsp
<%-- 角色(通过roleid)-的模块权限 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="../../base.jsp" %>
<!DOCTYPE html>
<html>
<head>
<!-- 页面meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>SaaS-Export 角色的模块树</title>
<meta name="description" content="SaaS-Export 角色的模块树">
<meta name="keywords" content="SaaS-Export module tree">
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
<!-- 页面meta /-->
<%--步骤:
第一步:拷贝zTree的css/js文件到项目中
第二步:拷贝js导入到当前页面
第三步:页面定义显示树的区域
--%>
<%--拷贝zTree的js脚本、css样式导入到当前页面--%>
<link rel="stylesheet" type="text/css" href="${path}/plugins/ztree/css/zTreeStyle/zTreeStyle.css">
<script type="text/javascript" src="${path}/plugins/ztree/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="${path}/plugins/ztree/js/jquery.ztree.all-3.5.min.js"></script>
<script type="text/javascript">
//当前的配置信息
var setting = {
check: {
enable: true
},
data: {
simpleData: {
enable: true
}
}
};
//zTree的数据(模拟数据)
//pId是树形菜单的等级(0最高) open:true,就是菜单是打开的(显示子菜单)
//checked:true 默认选中
/*var zNodes =[
{ id:1, pId:0, name:"Sass管理", open:true},
{ id:11, pId:1, name:"企业管理", open:true,checked:true},
{ id:111, pId:1, name:"模块管理"},
{ id:112, pId:1, name:"用户管理"},
{ id:113, pId:1, name:"角色管理"}
];*/
$(document).ready(function(){
var fn =function(data){
//菜单的初始化
//参1 显示的标签 参2 设置的参数 比如支持复选 check enable = true 参3 数据
$.fn.zTree.init($("#treeDemo"), setting, data);
}
//通过角色的id(roleId)来获取角色的模块权限信息
$.get('${path}/system/role/getZtreeData?roleId=${role.roleId}',fn,'json')
});
</script>
</head>
<body style="overflow: visible;">
<div id="frameContent" class="content-wrapper" style="margin-left:0px;height: 1200px" >
<section class="content-header">
<h1>
菜单管理
<small>菜单列表 - 角色模块</small>
</h1>
<ol class="breadcrumb">
<li><a href="all-admin-index.html"><i class="fa fa-dashboard"></i> 首页</a></li>
</ol>
</section>
<!-- 内容头部 /-->
<!-- 正文区域 -->
<section class="content">
<!-- .box-body -->
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">角色 [ ${role.name} ] 权限(模块)列表</h3>
</div>
<div class="box-body">
<!-- 数据表格 -->
<div class="table-box">
<!--工具栏-->
<div class="box-tools text-left">
<button type="button" class="btn bg-maroon" onclick="submitCheckedNodes();">保存</button>
<button type="button" class="btn bg-default" onclick="history.back(-1);">返回</button>
</div>
<!--工具栏/-->
<!-- 树菜单 -->
<script type="text/javascript">
function submitCheckedNodes() {
//先读取树状菜单的moduleId,再拼接成 201,202,203 赋值给隐藏框
var tree= $.fn.zTree.getZTreeObj("treeDemo");
//再获取选中的moduleId
//tree.getCheckedNodes(true); 返回被选中的节点,放在一个数组中
var nodes = tree.getCheckedNodes(true);
var moduleIds = ''
for(var i = 0;i<nodes.length;i++){
console.info(nodes[i])
var moduleId = nodes[i].id
moduleIds += moduleId
//201,202,203 如果是最后一个元素,不需要拼接,
if(i != nodes.length-1){
moduleIds += ','
}//end if
}//end for
console.info("moduleIds = "+moduleIds)
//将得到的moduleIds 设置给隐藏输入框,方便提交到后台控制器
$('#moduleIds').val(moduleIds)
//提交表单
$('#icform').submit()
}
</script>
<%-- zTree角色权限树,打钩就是拥有权限 --%>
<form id="icform" method="post" action="${path}/system/role/updateRoleModule">
<%-- 隐藏域角色id,后台需要根据id对角色权限进行更新 --%>
<input type="hidden" name="roleId" value="${role.roleId}"/>
<!-- 先读取树状菜单的moduleId,再拼接成 201,202,203 赋值给隐藏框-->
<input type="hidden" id="moduleIds" name="moduleIds" value=""/>
<div class="content_wrap">
<div class="zTreeDemoBackground left" style="overflow: visible">
<%-- 将模块显示出来 --%>
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</form>
<!-- 树菜单 /-->
</div>
<!-- /数据表格 -->
</div>
<!-- /.box-body -->
</div>
</section>
</div>
</body>
</html>