RBAC
主要内容
1.RBAC的介绍
2.传统项目数据库设计方案
3.RBAC设计方案
4.RBAC的详细版本
5.URL权限控制
一.RBAC简介
[1]RBAC的概念
基于角色的权限访问控制(Role-Based Access Control)作为传动访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注.在RBAC中,权限与角色相关连,用户通过称为适当角色的成员而得到这些角色的权限.这就极大的简化了权限的管理rbac:一种数据库设计思想,根据设计数据库设计方案,完成项目的权限控制
[2]权限的使用情景
2.1不同用户登录后看到的菜单是不一样的
2.2不同用户看到的页面效果不一样
2.2.1有的用户可以看到"授权"按钮,或有的用户可以看见"删除"按钮
2.3不同用户完成的功能是不一样的
2.3.1有的用户可以执行删除,有的可以执行新增
2.4场景示意图
小公司和比较简单的权限系统使用的基于用户的访问控制如下
这种访问控制只适用于操作人员比较少的系统,如果操作人员较多,对每个操作人员都进行授权操作,无疑是非常繁琐的.所以我们就需要基于角色的访问控制
[3]学习RBAC需要掌握的要素
3.1如何设计数据库中表
3.2如何根据数据库完成项目
3.3RBAC核心是角色,在数据库设计时一定有角色
3.4根据RBAC设计思想,设计出来的方案是非常灵活的
二.实现技术设计方案
[1]需求实现方案一
使用C:if判断的方式进行实现,和中级书写的SXTOA一样,在left中动态的判断该用户下的标签即可
缺点:
(1)所有的菜单标签必须提前的书写好.不可以更改
(2)如果需要添加菜单,只能更改源代码
[2]需求实现方案二
数据库结构实现如图所示
缺点:
(1)新建一个用户时,在用户表中添加一条数据
(2)新建一个用户时,在关联表中添加N条数据
(3)每次新建一个用户需要添加:1+N(关联几个)条数据
[3]需求实现方案三
1.基于RBAC的设计方案
1.1设定好在某些情况下哪些菜单需要被关联
1.1.1例如:管理员可以看到所有菜单
1.1.2例如:销售总监可以看到"销售管理"菜单
1.1.3例如:普通员工只能看见系统公告中公告查看
2.2现实生活中的职位对应1个或多个数据库中的角色
2.在系统上线后,会在程序中添加几种比较常见的角色,并把菜单和角色关联
3.1以后每次新建用户时
3.2在用户表中添加一个数据
3.3在用户和角色关联表中添加1条或n条数据
3.画图说明RBAC:
三.RBAC具体实现
[1]实现需求
使用RBAC数据库设计思想,完成不同的用户登录系统后显示不同的菜单
[2]功能分析
用户:张三和李四
菜单
用户管理
用户查询
增加用户
班级管理
班级查询
增加班级
查看通告
系统设置
[3]数据库设计
[4]数据库Sql语句
/*用户表--新增角色rid*/
/**角色表**/
create table role(
rid INT(5) PRIMARY KEY AUTO_INCREMENT,
rname VARCHAR(55)
);
INSERT INTO role VALUES(DEFAULT,'管理员工');
INSERT INTO role VALUES(DEFAULT,'管理员');
/**菜单表**/
CREATE TABLE menu(
mmid INT(5) PRIMARY KEY AUTO_INCREMENT,
mname VARCHAR(55),
URL varchar(55),
pid INT(5)
);
/**角色-菜单表**/
create table role_menu(
rid INT(5),
MMID INT(5)
);
/*给不同的角色赋予菜单*/
insert into role_menu values(1,2);
insert into role_menu values(1,3);
insert into role_menu values(1,6);
insert into role_menu values(1,8);
insert into role_menu values(1,9);
insert into role_menu values(1,10);
insert into role_menu values(2,1);
insert into role_menu values(2,2);
insert into role_menu values(2,3);
insert into role_menu values(2,4);
insert into role_menu values(2,5);
insert into role_menu values(2,6);
insert into role_menu values(2,7);
insert into role_menu values(2,8);
insert into role_menu values(2,9);
insert into role_menu values(2,10);
/*用户登录成功查询该角色下的所有菜单 用户登录成功就知道了rid=1*/
/*在role_menu表中查询指定角色中所有菜单的id*/
select mmid from role_menu where rid=1
/*在去menu表中查询指定mmid对应的菜单*/
select * from menu where mmid in(select mmid from role_menu where rid=2)and pid=1
[5]代码效果实现
5.1登录jsp页面
<div style="margin-top:120px; margin-left:407px;">
<div id="di" class="easyui-panel" title="登录" style="width:400px;height:300px;data-options="iconCls:'icon-help',closable:false,collapsible:false,minimizable:true,maximizable:true">
<div style="text-align:center;margin-top:80px;">
<form>
<div style="margin-bottom:25px;">
<span>用户名</span>
<input type="text" name="name" class="easyui-textbox" data-opyions="required:true"/>
</div>
<div style="margin-botton:25px;">
<span>密  码</span>
<input type="text" name="pwd" class="easyui-passwordbox" data-options="required:true"/>
</div>
<div>
<a onclick="javascript:void(0)" class="easyui-linkbutton" data-options="inonCls:'icon-clear'">提交</a>
<a onclick="javascript:void(0)" class="easyui-linkbutton" data-options="inonCls:'icon-clear'">清空</a>
</div>
</form>
</div>
</div>
</div>
5.2Mapper层代码
//查询菜单操作
@Select("select * from menu where mmid in(select mmid from role_menu where rid=#{param1}) and pid=#{param2}")
List<Menu> selectMore(int rid,int pid);
5.3Service层代码
@Override
public List<Tree>findMoreMenu(int rid,int pid){
List<Menu>list = menuMapper.selectMore(rid,pid);
List<Tree> lsit2 = new ArrayList<>();
for(Menu menu:list){
Tree tree = new Tree(menu.getMmid(),menu.getMname(),menu.getState()==1?"open":"closed");
//把指定的url地址保存到tree
tree.setUrl(menu.getUrl());
list2.add(tree);
}
return list2;
}
5.4Controller层代码
@RequestMappoing("/findMoreMenus")
public List<Tree>findMoreMenus(@RequestParam(defaultValue="0")int id,HttpSession session){
User user = (User)session.getAttribute("user");
return menuService.findMoreMenu(user.getRid(),id);
}
5.5运行截图
四.RBAC详细版本
[1]数据库设计
1.1权限表:平时小型项目中可以省略
1.2用户组表:对用户进行分组,每个用户组绑定多个角色,把用户放入到用户组后,具有对应多个角色
1.3角色组:角色组对应多个角色,用户组和角色组
1.4完成访问控制时,需要对什么类型表进行访问控制(在简单版中)把需要控制的内容和角色进行直接关联
[2]详细版中是跟权限进行关联
五.URL权限控制
1.目前的问题
访问通过URL非法操作,例如:在浏览器中直接通过URL访问控制器
2.解决方案
区分开:和页面元素可见权限
2.1页面元素可见:在页面能不能看到某些内容
2.2URL权限指:在浏览器地址栏直接访问
3.实现思想(基于简单版)
3.1添加URL表:
3.2URL表和角色表进行关联
3.3在filter或拦截器中天啊及权限验证
4.代码实现实例
4.1数据库设计
在当前rbac案例中新增一张url权限信息表
表名:t_url
作用:存储需要被管理的url地址信息
字段:编号,url地址
在当前rbac案例中新增一张角色和url权限表的关联表
表名:r_url
作用:存储需要被管理的url地址和信息
字段:编号,url地址
在当前rbac案例总新增一张角色和url权限表的关联表
表名:r_url
作用:表名url和角色之间的关联关系
字段:角色id,url的编号
Sql语句实例:
4.2代码实现
实现思路:
在项目增加过滤器,在过滤器中判断当前请求的url地址和用户具备的操作的URL地址是否一致.如果一致则放行,不一致则拦截,并提示器权限不足
过滤器代码示例:
public class LoginFilter2 implements Filter{
@Override
public void init(FilterConfig filterConfig)throws ServletException{
}
@Override
public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throws IOException,ServletException{
//登录权限的校验
HttpServeltRequest req = (HttpServletRequest)servletRequest;
HttpServletResponse resp = (HttpServletResponse)servletResponse;
//获取用户输入的名称
String uri = req.getRequestURI();
if("/ty/login.jsp".equals(uri)||"/ty/UserController/userLogin".equals(uri)){
filterChain.doFilter(req,resp);
}else{
User user = (User)req.getSession().getAttribute("user");
if(user!=null){
List<Url>list = user.getList();
for(Url u:lsit){
String url = "/ty/u.getUrl()";
System.out.println(url);
if(uri.equals(url)){
fileterChain.deFilter(req,resp);
return;
}
}
resp.getWriter().print("<script type='text/javascript'>alert('ERROR')</script>")
}else{
//判断当前请求是否是ajax请求
if("XMLHttpRequest".equals(req.getheader("X-Requested-With"))){
System.out.println("ajax中Session跳转页面");
resp.setHeader("sessionstatus","timeout");
resp.setHeader("redirectUrl","/ty/login.jsp");
}else{
resp.sendRedirect("/ty/loging.jsp");
}
}
}
}
@Override
public void destrop(){}
}
页面引入jquery ajax请求的通用代码(特定ajax请求处理后执行)
$.ajaxSetup({
contextType:"application/x-www-form-urlencoded;charset=utf-8",
complete:function(XMLHttpRequest,textStatus){
//通过XNLHttpRequest取得响应头,sessionstatus
var sessionstatus = XMLHttpRequest.getResponseHeader("sessionstatus");
if(sessionstatus=="timeout"){
//这里怎么处理在你,这里跳转的登录页面
window.location.replace(XMLHttpRequest.getResponseHeader("redirectUrl"));
}
}
})