赞
踩
Role-Based Access Control
基于角色的访问控制(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意思就是 分类 列表,无非就是为了看明白该数据是实现那个业务逻辑,没什么特殊用意!!!
菜单排序则是商品管理是所有一级菜单中的第二个,商品分类是商品管理的第一个二级菜单,商品信息是商品管理的第二个二级菜单。
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。
<%@ 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就可以获取到。
代码源码:
<%@ 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页面。
每个角色信息后面都有一个授权按钮,点击之后会根据不同的角色,显示当前角色具备的功能并“打钩”,其他功能则不“打钩”,效果如下:
当是超级管理员时:
商品管理员时:
那么是如何实现的呢???
上述的菜单树其实是一个图层,
<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。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。