幸運快三原始碼出售Shiro入門這篇就夠了
前言
本文主要講解的知識點有以下:
- 許可權管理的基礎知識
- 模型
- 粗粒度和細粒度的概念
- 回顧URL攔截的實現
- Shiro的介紹與簡單入門
一、Shiro基礎知識
在學習Shiro這個框架之前,首先我們要先了解Shiro需要的基礎知識:許可權管理
1.1什麼是許可權管理?
只要有使用者參與的系統一般都要有許可權管理,許可權管理實現對使用者訪問系統的控制,按照安全規則或者安全策略控制使用者可以訪問而且只能訪問自己被授權的資源。
對許可權的管理又分為兩大類別:
- 使用者認證
- 使用者授權
1.1.1使用者認證
使用者認證,使用者去訪問系統,系統要驗證使用者身份的合法性
最常用的使用者身份驗證的方法:1、使用者名稱密碼方式、2、指紋打卡機、3、基於證書驗證方法。。系統驗證使用者身份合法,使用者方可訪問系統的資源。
舉個例子:
- 當我們輸入了自己的淘寶的賬戶和密碼,才能開啟購物車
使用者認證的流程:
- 判斷該資源能否不認證就能訪問【登陸頁面、首頁】
- 如果該資源需要認證後才能訪問,那麼判斷該訪問者是否認證了
- 如果還沒有認證,那麼需要返回到【登陸頁面】進行認證
- 認證通過後才能訪問資源
從使用者認證我們可以抽取出這麼幾個概念
- subject主體:理解為使用者,可能是程式,都要去訪問系統的資源,系統需要對subject進行身份認證
- principal身份資訊:通常是唯一的,一個主體還有多個身份資訊,但是都有一個主身份資訊(primary principal)【我們可以選擇身份證認證、學生證認證等等都是我們的身份資訊】
- credential憑證資訊:可以是密碼 、證書、指紋。
總結:主體在進行身份認證時需要提供身份資訊和憑證資訊。
1.1.2使用者授權
使用者授權,簡單理解為訪問控制,在使用者認證通過後,系統對使用者訪問資源進行控制,使用者具有資源的訪問許可權方可訪問。
使用者授權的流程
- 到達了使用者授權環節,當然是需要使用者認證之後了
- 使用者訪問資源,系統判斷該使用者是否有許可權去操作該資源
- 如果該使用者有許可權才能夠訪問,如果沒有許可權就不能訪問了
授權的過程可以簡單理解為:主體認證之後,系統進行訪問控制
subject必須具備資源的訪問許可權才可訪問該資源..
許可權/許可(permission) :針對資源的許可權或許可幸運快三原始碼出售(www.1159880099.com)QQ1159880099 微信 Tel17061863533 平臺出租,原始碼出售,,subject具有permission訪問資源,如何訪問/操作需要定義permission
資源可以分為兩種
- 資源型別:系統的使用者資訊就是資源型別,相當於java類。
- 資源例項:系統中id為001的使用者就是資源例項,相當於new的java物件。
1.2許可權管理模型
一般地,我們可以抽取出這麼幾個模型:
- 主體(賬號、密碼)
- 資源(資源名稱、訪問地址)
- 許可權(許可權名稱、資源id)
- 角色(角色名稱)
- 角色和許可權關係(角色id、許可權id)
- 主體和角色關係(主體id、角色id)
通常企業開發中將資源和許可權表合併為一張許可權表,如下:
- 資源(資源名稱、訪問地址)
- 許可權(許可權名稱、資源id)
合併為:
- 許可權(許可權名稱、資源名稱、資源訪問地址)
1.3分配許可權
使用者需要分配相應的許可權才可訪問相應的資源。許可權是對於資源的操作許可。
通常給使用者分配資源許可權需要將許可權資訊持久化,比如儲存在關係資料庫中。把使用者資訊、許可權管理、使用者分配的許可權資訊寫到資料庫(許可權資料模型)
1.3.1基於角色訪問控制
RBAC(role based access control),基於角色的訪問控制。
//如果該user是部門經理則可以訪問if中的程式碼
if(user.hasRole('部門經理')){
//系統資源內容
//使用者報表檢視
}
角色針對人劃分的,人作為使用者在系統中屬於活動內容,如果該 角色可以訪問的資源出現變更,需要修改你的程式碼了,
if(user.hasRole('部門經理') || user.hasRole('總經理') ){
//系統資源內容
//使用者報表檢視
}
基於角色的訪問控制是不利於系統維護(可擴充套件性不強)。
1.3.2基於資源的訪問控制
RBAC(Resource based access control),基於資源的訪問控制。
資源在系統中是不變的,比如資源有:類中的方法,頁面中的按鈕。
對資源的訪問需要具有permission許可權,程式碼可以寫為:
if(user.hasPermission ('使用者報表檢視(許可權識別符號)')){
//系統資源內容
//使用者報表檢視
}
建議使用基於資源的訪問控制實現許可權管理。
二、 粗粒度和細粒度許可權
細粒度許可權管理:對資源例項的許可權管理。資源例項就資源型別的具體化,比如:使用者id為001的修改連線,1110班的使用者資訊、行政部的員工。細粒度許可權管理就是資料級別的許可權管理。
粗粒度許可權管理比如:超級管理員可以訪問戶新增頁面、使用者資訊等全部頁面。部門管理員可以訪問使用者資訊頁面包括 頁面中所有按鈕。
粗粒度和細粒度例子:
系統有一個使用者列表查詢頁面,對使用者列表查詢分許可權,
如果粗顆粒管理,張三和李四都有使用者列表查詢的許可權,張三和李四都可以訪問使用者列表查詢。
進一步進行細顆粒管理,張三(行政部)和李四(開發部)只可以查詢自己本部門的使用者資訊。
張三隻能檢視行政部 的使用者資訊,李四隻能檢視開發部門的使用者資訊。
細粒度許可權管理就是資料級別的許可權管理。
2.1如何實現粗粒度許可權管理?
粗粒度許可權管理比較容易將許可權管理的程式碼抽取出來在系統架構級別統一處理。比如:通過springmvc的攔截器實現授權。
對細粒度許可權管理在資料級別是沒有共性可言,針對細粒度許可權管理就是系統業務邏輯的一部分,在業務層去處理相對比較簡單
比如:部門經理只查詢本部門員工資訊,在service介面提供一個部門id的引數,controller中根據當前使用者的資訊得到該 使用者屬於哪個部門,呼叫service時將部門id傳入service,實現該使用者只查詢本部門的員工。
2.1.1基於URL攔截
基於url攔截的方式實現在實際開發中比較常用的一種方式。
對於web系統,通過filter過慮器實現url攔截,也可以springmvc的攔截器實現基於url的攔截。
2.2.2使用許可權管理框架實現
對於粗粒度許可權管理,建議使用優秀許可權管理框架來實現,節省開發成功,提高開發效率。
shiro就是一個優秀許可權管理框架。
三、回顧URL攔截
我們在學習的路途上也是使用過幾次URL對許可權進行攔截的
當時我們做了許可權的增刪該查的管理系統,但是在許可權表中是沒有把資源新增進去,我們使用的是Map集合來進行替代的。 blog.csdn.net/hon_3y/arti…
隨後,我們學習了動態代理和註解,我們也做了一個基於註解的攔截
- 在Controller得到service物件的時候,service工廠返回的是一個動態代理物件回去
- Controller拿著代理物件去呼叫方法,代理物件就會去解析該方法上是否有註解
- 如果有註解,那麼就需要我們進行判斷該主體是否認證了,如果認證了就判斷該主體是否有許可權
- 當我們解析出該主體的許可權和我們註解的許可權是一致的時候,才放行!
流程:
3.1認證的JavaBean
我們之前認證都是放在預設的Javabean物件上的,現在既然我們準備學Shiro了,我們就得專業一點,弄一個專門儲存認證資訊的JavaBean
/**
* 使用者身份資訊,存入session 由於tomcat將session會序列化在本地硬碟上,所以使用Serializable介面
*
* @author Thinkpad
*
*/publicclassActiveUserimplementsjava.io.Serializable{
private String userid;//使用者id(主鍵)private String usercode;// 使用者賬號private String username;// 使用者名稱稱private List<SysPermission> menus;// 選單private List<SysPermission> permissions;// 許可權public String getUsername(){
return username;
}
publicvoidsetUsername(String username){
this.username = username;
}
public String getUsercode(){
return usercode;
}
publicvoidsetUsercode(String usercode){
this.usercode = usercode;
}
public String getUserid(){
return userid;
}
publicvoidsetUserid(String userid){
this.userid = userid;
}
public List<SysPermission> getMenus(){
return menus;
}
publicvoidsetMenus(List<SysPermission> menus){
this.menus = menus;
}
public List<SysPermission> getPermissions(){
return permissions;
}
publicvoidsetPermissions(List<SysPermission> permissions){
this.permissions = permissions;
}
}
認證的服務
@Override
public ActiveUser authenticat(String userCode, String password)
throws Exception {
/**
認證過程:
根據使用者身份(賬號)查詢資料庫,如果查詢不到使用者不存在
對輸入的密碼 和資料庫密碼 進行比對,如果一致,認證通過
*/
//根據使用者賬號查詢資料庫
SysUser sysUser = this.findSysUserByUserCode(userCode);
if(sysUser == null){
//丟擲異常
throw new CustomException("使用者賬號不存在");
}
//資料庫密碼 (md5密碼 )
String password_db = sysUser.getPassword();
//對輸入的密碼 和資料庫密碼 進行比對,如果一致,認證通過
//對頁面輸入的密碼 進行md5加密
String password_input_md5 = new MD5().getMD5ofStr(password);
if(!password_input_md5.equalsIgnoreCase(password_db)){
//丟擲異常
throw new CustomException("使用者名稱或密碼 錯誤");
}
//得到使用者id
String userid = sysUser.getId();
//根據使用者id查詢選單
List<SysPermission> menus =this.findMenuListByUserId(userid);
//根據使用者id查詢許可權url
List<SysPermission> permissions = this.findPermissionListByUserId(userid);
//認證通過,返回使用者身份資訊
ActiveUser activeUser = new ActiveUser();
activeUser.setUserid(sysUser.getId());
activeUser.setUsercode(userCode);
activeUser.setUsername(sysUser.getUsername());//使用者名稱稱
//放入許可權範圍的選單和url
activeUser.setMenus(menus);
activeUser.setPermissions(permissions);
return activeUser;
}
Controller處理認證,如果身份認證成功,那麼把認證資訊儲存在Session中
@RequestMapping("/login")
public String login(HttpSession session, String randomcode,String usercode,String password)throws Exception{
//校驗驗證碼,防止惡性攻擊
//從session獲取正確驗證碼
String validateCode = (String) session.getAttribute("validateCode");
//輸入的驗證和session中的驗證進行對比
if(!randomcode.equals(validateCode)){
//丟擲異常
throw new CustomException("驗證碼輸入錯誤");
}
//呼叫service校驗使用者賬號和密碼的正確性
ActiveUser activeUser = sysService.authenticat(usercode, password);
//如果service校驗通過,將使用者身份記錄到session
session.setAttribute("activeUser", activeUser);
//重定向到商品查詢頁面
return "redirect:/first.action";
}
身份認證攔截器
//在執行handler之前來執行的//用於使用者認證校驗、使用者許可權校驗
@Override
publicboolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//得到請求的urlString url = request.getRequestURI();
//判斷是否是公開 地址//實際開發中需要公開 地址配置在配置檔案中//從配置中取逆名訪問url
List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL");
//遍歷公開 地址,如果是公開 地址則放行for(String open_url:open_urls){
if(url.indexOf(open_url)>=0){
//如果是公開 地址則放行returntrue;
}
}
//判斷使用者身份在session中是否存在
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
//如果使用者身份在session中存在放行if(activeUser!=null){
returntrue;
}
//執行到這裡攔截,跳轉到登陸頁面,使用者進行身份認證
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
//如果返回false表示攔截不繼續執行handler,如果返回true表示放行returnfalse;
}
授權攔截器
//在執行handler之前來執行的
//用於使用者認證校驗、使用者許可權校驗
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//得到請求的url
String url = request.getRequestURI();
//判斷是否是公開 地址
//實際開發中需要公開 地址配置在配置檔案中
//從配置中取逆名訪問url
List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL");
//遍歷公開 地址,如