1、受權的三要素html
受權有着三個核心元素:權限、角色和用戶。java
權限 apache
權限是Apache Shiro安全機制最核心的元素。它在應用程序中明確聲明瞭被容許的行爲和表現。一個格式良好好的權限聲明能夠清晰表達出用戶對該資源擁有的權限。 安全
大多數的資源會支持典型的CRUD操做(create,read,update,delete),可是任何操做創建在特定的資源上纔是有意義的。所以,權限聲明的根本思想就是創建在資源以及操做上。 jsp
而咱們經過權限聲明僅僅能瞭解這個權限能夠在應用程序中作些什麼,而不能肯定誰擁有此權限。ui
因而,咱們就須要在應用程序中對用戶和權限創建關聯。 一般的作法就是將權限分配給某個角色,而後將這個角色關聯一個或多個用戶。 this
權限聲明及粒度編碼
Shiro權限聲明一般是使用以冒號分隔的表達式。就像前文所講,一個權限表達式能夠清晰的指定資源類型,容許的操做,可訪問的數據。同時,Shiro權限表達式支持簡單的通配符,能夠更加靈活的進行權限設置。spa
下面以實例來講明權限表達式。
設計
可查詢用戶數據 User:view
可查詢或編輯用戶數據 User:view,edit
可對用戶數據進行全部操做 User:* 或 user
可編輯id爲123的用戶數據 User:edit:123
角色
Shiro支持兩種角色模式:
一、傳統角色:一個角色表明着一系列的操做,當須要對某一操做進行受權驗證時,只需判斷是不是該角色便可。這種角色權限相對簡單、模糊,不利於擴展。
二、權限角色:一個角色擁有一個權限的集合。受權驗證時,須要判斷當前角色是否擁有該權限。這種角色權限能夠對該角色進行詳細的權限描述,適合更復雜的權限設計。
下面將詳細描述對兩種角色模式的受權實現。
2、受權實現
Shiro支持三種方式實現受權過程:
編碼實現
註解實現
JSP Taglig實現
一、基於編碼的受權實現
1.1基於傳統角色受權實現
當須要驗證用戶是否擁有某個角色(1)時,能夠調用Subject 實例的hasRole*(2)方法驗證。
Subject currentUser = SecurityUtils.getSubject(); if (currentUser.hasRole("administrator")) { //show the admin button } else { //don't show the button? Grey it out? }
相關驗證方法以下:
斷言支持
Shiro還支持以斷言的方式進行受權驗證。斷言成功,不返回任何值,程序繼續執行;斷言失敗時,將拋出異常信息。使用斷言,可使咱們的代碼更加簡潔。
Subject currentUser = SecurityUtils.getSubject(); //guarantee that the current user is a bank teller and //therefore allowed to open the account: currentUser.checkRole("bankTeller"); openBankAccount();
斷言的相關方法:
1.2 基於權限角色受權實現
相比傳統角色模式,基於權限的角色模式耦合性要更低些,它不會因角色的改變而對源代碼進行修改,所以,基於權限的角色模式是更好的訪問控制方式。
它的代碼實現有如下幾種實現方式:
一、基於權限對象的實現
建立org.apache.shiro.authz.Permission的實例(1),將該實例對象做爲參數傳遞給Subject.isPermitted()進行驗證(2)。
Permission printPermission = new PrinterPermission("laserjet4400n", "print"); Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted(printPermission)) { //show the Print button } else { //don't show the button? Grey it out? }
相關方法以下:
二、 基於字符串的實現
相比笨重的基於對象的實現方式,基於字符串的實現便顯得更加簡潔。
Subject currentUser = SecurityUtils.getSubject(); if (currentUser.isPermitted("printer(資源類型):print(操做):laserjet4400n(資源ID)")) { //show the Print button } else { //don't show the button? Grey it out? }
使用冒號分隔的權限表達式是org.apache.shiro.authz.permission.WildcardPermission 默認支持的實現方式。
這裏分別表明了 資源類型:操做:資源ID
相似基於對象的實現相關方法,基於字符串的實現相關方法:
isPermitted(String perm)、isPermitted(String... perms)、isPermittedAll(String... perms)
基於權限對象的斷言實現
Subject currentUser = SecurityUtils.getSubject(); //guarantee that the current user is permitted //to open a bank account: Permission p = new AccountPermission("open"); currentUser.checkPermission(p); openBankAccount();
基於字符串的斷言實現
Subject currentUser = SecurityUtils.getSubject(); //guarantee that the current user is permitted //to open a bank account: currentUser.checkPermission("account:open"); openBankAccount();
斷言實現的相關方法
二、基於註解的受權實現
Shiro註解支持AspectJ、Spring、Google-Guice等,可根據應用進行不一樣的配置。
相關的註解:
@ RequiresAuthentication
能夠用戶類/屬性/方法,用於代表當前用戶需是通過認證的用戶。
@RequiresAuthentication public void updateAccount(Account userAccount) { //this method will only be invoked by a //Subject that is guaranteed authenticated ... }
@ RequiresGuest
代表該用戶需爲」guest」用戶
@ RequiresPermissions
當前用戶需擁有制定權限
@RequiresPermissions("account:create") public void createAccount(Account account) { //this method will only be invoked by a Subject //that is permitted to create an account ... }
@RequiresRoles
當前用戶需擁有制定角色
@ RequiresUser
當前用戶需爲已認證用戶或已記住用戶
三、基於JSP TAG的受權實現
Shiro提供了一套JSP標籤庫來實現頁面級的受權控制。
在使用Shiro標籤庫前,首先須要在JSP引入shiro標籤:
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
下面一一介紹Shiro的標籤:
guest標籤
驗證當前用戶是否爲「訪客」,即未認證(包含未記住)的用戶
<shiro:guest> Hi there! Please <a href="login.jsp">Login</a> or <a href="signup.jsp">Signup</a> today! </shiro:guest>
user標籤
認證經過或已記住的用戶
<shiro:user> Welcome back John! Not John? Click <a href="login.jsp">here<a> to login. </shiro:user>
authenticated標籤
已認證經過的用戶。不包含已記住的用戶,這是與user標籤的區別所在。
<shiro:authenticated> <a href="updateAccount.jsp">Update your contact information</a>. </shiro:authenticated>
notAuthenticated標籤
未認證經過用戶,與authenticated標籤相對應。與guest標籤的區別是,該標籤包含已記住用戶。
<shiro:notAuthenticated> Please <a href="login.jsp">login</a> in order to update your credit card information. </shiro:notAuthenticated>
principal 標籤
輸出當前用戶信息,一般爲登陸賬號信息
Hello, <shiro:principal/>, how are you today?
hasRole標籤
驗證當前用戶是否屬於該角色
<shiro:hasRole name="administrator"> <a href="admin.jsp">Administer the system</a> </shiro:hasRole>
lacksRole標籤
與hasRole標籤邏輯相反,當用戶不屬於該角色時驗證經過
<shiro:lacksRole name="administrator"> Sorry, you are not allowed to administer the system. </shiro:lacksRole>
hasAnyRole標籤
驗證當前用戶是否屬於如下任意一個角色。
<shiro:hasAnyRoles name="developer, project manager, administrator"> You are either a developer, project manager, or administrator. </shiro:lacksRole>
hasPermission標籤
驗證當前用戶是否擁有制定權限
<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission>
lacksPermission標籤
與hasPermission標籤邏輯相反,當前用戶沒有制定權限時,驗證經過
<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a> </shiro:hasPermission>
3、Shiro受權的內部處理機制
一、在應用程序中調用受權驗證方法(Subject的isPermitted*或hasRole*等)
二、Sbuject的實例一般是DelegatingSubject類(或子類)的實例對象,在認證開始時,會委託應用程序設置的securityManager實例調用相應的isPermitted*或hasRole*方法。
三、接下來SecurityManager會委託內置的Authorizer的實例(默認是ModularRealmAuthorizer 類的實例,相似認證明例,它一樣支持一個或多個Realm實例認證)調用相應的受權方法。
四、每個Realm將檢查是否實現了相同的 Authorizer 接口。而後,將調用Reaml本身的相應的受權驗證方法。
當使用多個Realm時,不一樣於認證策略處理方式,受權處理過程當中:
一、當調用Realm出現異常時,將當即拋出異常,結束受權驗證。
二、只要有一個Realm驗證成功,那麼將認爲受權成功,當即返回,結束認證。