RBAC
主要內(nèi)容
1.RBAC的介紹
2.傳統(tǒng)項(xiàng)目數(shù)據(jù)庫設(shè)計(jì)方案
3.RBAC設(shè)計(jì)方案
4.RBAC的詳細(xì)版本
5.URL權(quán)限控制
一.RBAC簡介
[1]RBAC的概念
基于角色的權(quán)限訪問控制(Role-Based Access Control)作為傳動(dòng)訪問控制(自主訪問,強(qiáng)制訪問)的有前景的代替受到廣泛的關(guān)注.在RBAC中,權(quán)限與角色相關(guān)連,用戶通過稱為適當(dāng)角色的成員而得到這些角色的權(quán)限.這就極大的簡化了權(quán)限的管理rbac:一種數(shù)據(jù)庫設(shè)計(jì)思想,根據(jù)設(shè)計(jì)數(shù)據(jù)庫設(shè)計(jì)方案,完成項(xiàng)目的權(quán)限控制
[2]權(quán)限的使用情景
2.1不同用戶登錄后看到的菜單是不一樣的
2.2不同用戶看到的頁面效果不一樣
2.2.1有的用戶可以看到"授權(quán)"按鈕,或有的用戶可以看見"刪除"按鈕
2.3不同用戶完成的功能是不一樣的
2.3.1有的用戶可以執(zhí)行刪除,有的可以執(zhí)行新增
2.4場景示意圖
小公司和比較簡單的權(quán)限系統(tǒng)使用的基于用戶的訪問控制如下
這種訪問控制只適用于操作人員比較少的系統(tǒng),如果操作人員較多,對每個(gè)操作人員都進(jìn)行授權(quán)操作,無疑是非常繁瑣的.所以我們就需要基于角色的訪問控制
[3]學(xué)習(xí)RBAC需要掌握的要素
3.1如何設(shè)計(jì)數(shù)據(jù)庫中表
3.2如何根據(jù)數(shù)據(jù)庫完成項(xiàng)目
3.3RBAC核心是角色,在數(shù)據(jù)庫設(shè)計(jì)時(shí)一定有角色
3.4根據(jù)RBAC設(shè)計(jì)思想,設(shè)計(jì)出來的方案是非常靈活的
二.實(shí)現(xiàn)技術(shù)設(shè)計(jì)方案
[1]需求實(shí)現(xiàn)方案一
使用C:if判斷的方式進(jìn)行實(shí)現(xiàn),和中級書寫的SXTOA一樣,在left中動(dòng)態(tài)的判斷該用戶下的標(biāo)簽即可
缺點(diǎn):
? ? (1)所有的菜單標(biāo)簽必須提前的書寫好.不可以更改
? ? (2)如果需要添加菜單,只能更改源代碼
[2]需求實(shí)現(xiàn)方案二
數(shù)據(jù)庫結(jié)構(gòu)實(shí)現(xiàn)如圖所示
缺點(diǎn):
(1)新建一個(gè)用戶時(shí),在用戶表中添加一條數(shù)據(jù)
(2)新建一個(gè)用戶時(shí),在關(guān)聯(lián)表中添加N條數(shù)據(jù)
(3)每次新建一個(gè)用戶需要添加:1+N(關(guān)聯(lián)幾個(gè))條數(shù)據(jù)
[3]需求實(shí)現(xiàn)方案三
1.基于RBAC的設(shè)計(jì)方案
1.1設(shè)定好在某些情況下哪些菜單需要被關(guān)聯(lián)
1.1.1例如:管理員可以看到所有菜單
1.1.2例如:銷售總監(jiān)可以看到"銷售管理"菜單
1.1.3例如:普通員工只能看見系統(tǒng)公告中公告查看
2.2現(xiàn)實(shí)生活中的職位對應(yīng)1個(gè)或多個(gè)數(shù)據(jù)庫中的角色
2.在系統(tǒng)上線后,會(huì)在程序中添加幾種比較常見的角色,并把菜單和角色關(guān)聯(lián)
3.1以后每次新建用戶時(shí)
3.2在用戶表中添加一個(gè)數(shù)據(jù)
3.3在用戶和角色關(guān)聯(lián)表中添加1條或n條數(shù)據(jù)
3.畫圖說明RBAC:
三.RBAC具體實(shí)現(xiàn)
[1]實(shí)現(xiàn)需求
使用RBAC數(shù)據(jù)庫設(shè)計(jì)思想,完成不同的用戶登錄系統(tǒng)后顯示不同的菜單
[2]功能分析
用戶:張三和李四
菜單
用戶管理
? ? 用戶查詢
? ? 增加用戶
班級管理
? ? 班級查詢
? ? 增加班級
查看通告
? ? 系統(tǒng)設(shè)置
[3]數(shù)據(jù)庫設(shè)計(jì)
[4]數(shù)據(jù)庫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對應(yīng)的菜單*/
select * from menu where mmid in(select mmid from role_menu where rid=2)and pid=1
[5]代碼效果實(shí)現(xiàn)
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運(yùn)行截圖
四.RBAC詳細(xì)版本
[1]數(shù)據(jù)庫設(shè)計(jì)
1.1權(quán)限表:平時(shí)小型項(xiàng)目中可以省略
1.2用戶組表:對用戶進(jìn)行分組,每個(gè)用戶組綁定多個(gè)角色,把用戶放入到用戶組后,具有對應(yīng)多個(gè)角色
1.3角色組:角色組對應(yīng)多個(gè)角色,用戶組和角色組
1.4完成訪問控制時(shí),需要對什么類型表進(jìn)行訪問控制(在簡單版中)把需要控制的內(nèi)容和角色進(jìn)行直接關(guān)聯(lián)
[2]詳細(xì)版中是跟權(quán)限進(jìn)行關(guān)聯(lián)
五.URL權(quán)限控制
1.目前的問題
訪問通過URL非法操作,例如:在瀏覽器中直接通過URL訪問控制器
2.解決方案
區(qū)分開:和頁面元素可見權(quán)限
2.1頁面元素可見:在頁面能不能看到某些內(nèi)容
2.2URL權(quán)限指:在瀏覽器地址欄直接訪問
3.實(shí)現(xiàn)思想(基于簡單版)
3.1添加URL表:
3.2URL表和角色表進(jìn)行關(guān)聯(lián)
3.3在filter或攔截器中天啊及權(quán)限驗(yàn)證
4.代碼實(shí)現(xiàn)實(shí)例
4.1數(shù)據(jù)庫設(shè)計(jì)
在當(dāng)前rbac案例中新增一張url權(quán)限信息表
表名:t_url
作用:存儲(chǔ)需要被管理的url地址信息
字段:編號,url地址
在當(dāng)前rbac案例中新增一張角色和url權(quán)限表的關(guān)聯(lián)表
表名:r_url
作用:存儲(chǔ)需要被管理的url地址和信息
字段:編號,url地址
在當(dāng)前rbac案例總新增一張角色和url權(quán)限表的關(guān)聯(lián)表
表名:r_url
作用:表名url和角色之間的關(guān)聯(lián)關(guān)系
字段:角色id,url的編號
Sql語句實(shí)例:
4.2代碼實(shí)現(xiàn)
實(shí)現(xiàn)思路:
在項(xiàng)目增加過濾器,在過濾器中判斷當(dāng)前請求的url地址和用戶具備的操作的URL地址是否一致.如果一致則放行,不一致則攔截,并提示器權(quán)限不足
過濾器代碼示例:
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{
? ? ? ? //登錄權(quán)限的校驗(yàn)
? ? ? ? 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{
? ? ? ? ? ? ? ? //判斷當(dāng)前請求是否是ajax請求
? ? ? ? ? ? ? ? if("XMLHttpRequest".equals(req.getheader("X-Requested-With"))){
? ? ? ? ? ? ? ? ? ? System.out.println("ajax中Session跳轉(zhuǎn)頁面");
? ? ? ? ? ? ? ? ? ? resp.setHeader("sessionstatus","timeout");
? ? ? ? ? ? ? ? ? ? resp.setHeader("redirectUrl","/ty/login.jsp");
????????????????}else{
? ? ? ? ? ? ? ? ? ? resp.sendRedirect("/ty/loging.jsp");
????????????????}
????????????}
????????}
????}
? ? @Override
? ? public void destrop(){}
}
頁面引入jquery ajax請求的通用代碼(特定ajax請求處理后執(zhí)行)
$.ajaxSetup({
? ? contextType:"application/x-www-form-urlencoded;charset=utf-8",
? ? complete:function(XMLHttpRequest,textStatus){
? ? ? ? //通過XNLHttpRequest取得響應(yīng)頭,sessionstatus
? ? ? ? var sessionstatus = XMLHttpRequest.getResponseHeader("sessionstatus");
? ? ? ? if(sessionstatus=="timeout"){
? ? ? ? ? ? //這里怎么處理在你,這里跳轉(zhuǎn)的登錄頁面
? ? ? ? ? ? window.location.replace(XMLHttpRequest.getResponseHeader("redirectUrl"));
? ? ? ? }
????}
})