基于角色的访问控制(RBAC)系统设计全过程(数据库以及java)项目
基于角色的访问控制(RBAC)一、基于角色的访问控制(RBAC)介绍什么是基于角色的访问控制(RBAC)Role-Based Access Control基于角色的访问控制(RBAC)百度百科其基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。一旦用户被分配了适当的角色后,该用户就拥有此角色的所有操作权限。这样做的好
基于角色的访问控制(RBAC)
一、基于角色的访问控制(RBAC)介绍
什么是基于角色的访问控制(RBAC)
Role-Based Access Control
基于角色的访问控制(RBAC)百度百科
其基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。
每一种角色对应一组相应的权限。
一旦用户被分配了适当的角色后,该用户就拥有此角色的所有操作权限。
这样做的好处是,不必在每次创建用户时都进行分配权限的操作,只要分配用户相应的角色即可,而且角色的权限变更比用户的权限变更要少得多,这样将简化用户的权限管理,减少系统的开销。
为什么要用RBAC
正如介绍中所说,不同的人拥有不同的权限,使得系统更加合理,分级治之!!!
二、RBAC的数据库设计
RBAC系统表设计思路
数据库表设计思路图
简单介绍下:
李四是这个系统的一个用户,他的角色是超级管理员admin,超级管理员的权限就是全部权限。
上述的五个表,只有三个表(用户表,角色表,菜单表)是真正的表,
用户角色表是将用户表和角色表通过主外键的关系相连接的,同样权限表就是将角色表和菜单表相互连接的表
数据库结构文件(用powerdesign打开)
用户表介绍
比较简单
角色表介绍
用户角色表
将用户表和角色表通过外键连接起来
菜单表介绍
这个表比较复杂,解释下
举个例子:
- 商品管理(一级菜单):
- 商品分类管理(二级菜单)
- 商品信息(二级菜单)
菜单编号(主键) | 菜单名称 | 父级菜单ID | 父级菜单名称 | 菜单类型(几级菜单) | 菜单URL | 菜单编码 | 菜单图标 | 菜单排序 |
---|---|---|---|---|---|---|---|---|
4 | 商品管理 | 0 | 1 | icon-product | 2 | |||
5 | 商品分类 | 4 | 商品管理 | 2 | crServelt?op=list | cr:list | con-cr-list | 1 |
6 | 商品信息 | 4 | 商品管理 | 2 | productServelt?op=list | product:list | icon-product-list | 2 |
这里的菜单编码如cr:list意思就是 分类 列表,无非就是为了看明白该数据是实现那个业务逻辑,没什么特殊用意!!!
菜单排序则是商品管理是所有一级菜单中的第二个,商品分类是商品管理的第一个二级菜单,商品信息是商品管理的第二个二级菜单。
数据库表和数据SQL源码
三、RBAC的功能实现
登录功能实现
login.jsp(不做重点介绍)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页</title>
</head>
<body>
<form method="post" action="/ebuy/systemUserServlet?op=login">
用户名:<input type="text" name="userName"><br>
密码:<input type="password" name="userPwd"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
看代码看得出登录页面设置十分简单,只有一个提交表单(后期完善吧)
form表单请求的是/ebuy/systemUserServlet?op=login
,一个servlet,并且传入参数op方便请求同一个servlet的不同方法。
当然登录是要访问数据库查询数据的,(代码后面留下来了,不重点说了!),根据用户名和密码来查询数据,dao层代码如下:
/**
* 具有权限控制的用户数据访问实现类
*/
public class SystemUserDaoImpl implements SystemUserDao {
@Override
public SystemUser login(SystemUser systemUser) {
Connection connection=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
String sql = "select * from system_userinfo where USERINFO_LOGINID=? and USERINFO_PASSWORD=? ";
connection = JDBCUtils.getConnection();
ps = connection.prepareStatement(sql);
ps.setString(1, systemUser.getUserinfo_loginid());
ps.setString(2,systemUser.getUserinfo_password());
rs = ps.executeQuery();
SystemUser systemUser1=createSystemUserByResultSet(rs);
if (systemUser1.getUserinfo_loginid()==null){
return null;
}else {
return systemUser1;
}
}catch (Exception e){
e.printStackTrace();
}
try {
rs.close();
ps.close();
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
private SystemUser createSystemUserByResultSet(ResultSet rs) throws SQLException {
SystemUser systemUser = new SystemUser();
while (rs.next()){
systemUser.setUserinfo_uid(rs.getString("userinfo_uid"));
systemUser.setUserinfo_loginid(rs.getString("userinfo_loginid"));
systemUser.setUserinfo_name(rs.getString("userinfo_name"));
systemUser.setUserinfo_password(rs.getString("userinfo_password"));
systemUser.setUserinfo_sex(rs.getString("userinfo_sex"));
systemUser.setUserinfo_email(rs.getString("userinfo_email"));
systemUser.setUserinfo_mobile(rs.getString("userinfo_mobile"));
systemUser.setUserinfo_status(rs.getInt("userinfo_status"));
}
return systemUser;
}
}
查询菜单功能
在登录成功后,我们根据登录用户的id来查询用户角色表中对应的角色id,然后通过角色菜单(权限表)来查询该用户的菜单项。
sql语句如下:
String sql = "select p.* from system_role_permission rp ,system_permission p where
rp.permission_id=p.permission_id and rp.role_id=( select r.role_id from system_userrole ur,system_userinfo
u,system_role r where ur.userinfo_id=u.userinfo_uid and ur.role_id=r.role_id and u.userinfo_loginid=?) ";
然后将查询到的菜单项打包成集合,返回至index.jsp进行遍历
index页面通过include指令指令包含了两个jsp,分别是admin-header.jsp和admin-left.jsp。
admin-header.jsp
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<base href="<%=basePath%>">
<head>
<link type="text/css" rel="stylesheet" href="css/style.css" />
<script type="text/javascript" src="scripts/function-manage.js"></script>
</head>
<div id="header" class="wrap">
<div id="logo"><img src="images/logo.gif" /></div>
<div class="help"><a href="index.jsp">返回前台页面</a></div>
<div class="navbar">
<ul class="clearfix">
<li class="current"><a href="manage/index.jsp">首页</a></li>
<li><a href="manage/user.html">用户</a></li>
<li><a href="manage/product.html">商品</a></li>
<li><a href="manage/order.html">订单</a></li>
<li><a href="manage/guestbook.html">留言</a></li>
<li><a href="manage/news.html">新闻</a></li>
</ul>
</div>
</div>
<div id="childNav">
<div class="welcome wrap">
管理员 ${sessionScope.USER.userinfo_name} 您好,今天是<%Date date=new Date();out.print(date);%>,欢迎回到管理后台。
</div>
</div>
<div id="position" class="wrap">
您现在的位置:<a href="index.jsp">易买网</a> > 管理后台
</div>
该页面就只有两个重点,一个是basepath,一个是显示用户名。
-
basepath
就是方便网页之间请求资源url的,不明白可以看这个 -
显示用户名
之前我们在登录请求servlet时,将查询到的用户表信息保存至session,通过jsp的session就可以获取到。
admin-left.jsp
代码源码:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8"%>
<html>
<head>
<title>Title</title>
</head>
<div id="menu-mng" class="lefter">
<div class="box">
<dl>
<c:forEach items="${sessionScope.systemPermissionList}" var="p1">
<c:if test="${p1.parent_id==0}">
<dt>${p1.permission_name}</dt>
<c:forEach items="${sessionScope.systemPermissionList}" var="p2">
<c:if test="${p2.parent_id!=0&&p2.parent_id==p1.permission_id}">
<dd><em><a href="productClass-add.html">新增</a></em><a href="${p2.permission_url}">${p2.permission_name}</a></dd>
</c:if>
</c:forEach>
</c:if>
</c:forEach>
</dl>
</div>
</div>
上述的代码适用于二级菜单(多级不适用,多级也会使得页面过于乱)
在标题的url上我们是根据数据库查询到的
实现角色管理
上述我们已经说了角色管理等标题的url是数据库中查询出来的,然后我们可以看到该角色管理的url:systemRoleServlet?op=list
,
可以看出是请求systemRoleServlet这个servlet,然后请求的方法是list,就是把数据库的role角色信息全部查询出来
dao层数据访问层直接查询全部的角色信息,保存至role的集合中,然后返回至roleList页面。
roleList和index页面一样,同样包含header页面和left页面。
授权按钮
每个角色信息后面都有一个授权按钮,点击之后会根据不同的角色,显示当前角色具备的功能并“打钩”,其他功能则不“打钩”,效果如下:
当是超级管理员时:
商品管理员时:
那么是如何实现的呢???
显示vtree树
上述的菜单树其实是一个图层,
<div id="bg">
</div>
<div id="show">
<span id="roleName"></span><br>
<input id="btnclose" type="button" value="close" onclick="hidediv();"/>
<ul id="treeDemo" class="ztree"></ul>
<input id="btnOK" type="button" value="OK" onclick="savePermission();"/>
</div>
</div>
当我们点击授权时,<a href="javascript:void(0);" onclick="showdiv('${role.role_id}','${role.role_name}')">授权</a>
,调用showdiv()方法,
shoudiv()方法:
var roleIds='';
function showdiv(roleId,roleName) {
roleIds=roleId;
//每点击一次进行一次刷新
document.getElementById("bg").style.display = "block";
document.getElementById("show").style.display = "block";
$("#roleName").html(roleName+"拥有的权限");
//ajax请求
$.ajax({
url:'systemPermissionServlet',
type:'post',
async:false,
data:{
op:'getPermissionTreeByRoleId',
roleId:roleId
},
dataType:'json',
success:function (data){
$.fn.zTree.init($("#treeDemo"), setting, data);
}
})
}
该方法首先就是使得图层显现出来,然后执行ajax请求,然后ajax请求成功之后就会调用success函数,初始化树,从而将该被勾选的数据进行勾选。
授权角色并保存至数据库
点击图层的ok按钮,触发savePermission()
方法,
function savePermission() {
var zTree = $.fn.zTree.getZTreeObj("treeDemo");
var nodes = zTree.getCheckedNodes();
var permissionIds='';
for (var i = 0; i < nodes.length; i++) {
if (i==nodes.length-1){
//最后一个不加逗号
permissionIds+=nodes[i].id;
//跳出循环
break;
}
permissionIds+=nodes[i].id+",";
};
$.ajax({
url:'systemPermissionServlet',
type:'post',
async:false,
data:{
op:'updatePermission',
/*全局变量,在点击授权时,在*showdiv方法中已经赋值*/
roleId:roleIds,
permissionIdArray:permissionIds
},
dataType:'json',
success:function (data){
alert(data.msg);
}
});
alert("授权完成");
hidediv();
}
同上面的显示vtree。
更多推荐
所有评论(0)