[翻譯-Shiro]-Apache Shiro Java 授權指南

劉曉日發表於2011-10-10

譯者:劉曉日

授權,也叫訪問控制,提供特定資源訪問許可權的功能。或者說是什麼樣的使用者可以訪問哪些特定資源。

授權檢查的例子有:使用者是否可以訪問某網頁,是否可以編輯資料,按鈕對其是否可見,或者是否允許列印等。這些都是由哪些使用者可以訪問哪些資源決定的。

授權組成部分

授權有三個核心要素:許可權、角色、使用者。

許可權定義

許可權是安全領域內的最小單元,且具有陳述功能性。許可權代表使用者可以使用應用程式完成哪些工作。一個定義良好的許可權不僅可以表述資源的型別,還可展示出在與資源互動時可進行哪些操作。比如:你有開啟門的許可權嗎?你對這個檔案有讀的許可權嗎?你能刪除客戶記錄嗎?這個按鈕你能點選嗎?

資料相關的操作有增、刪、改、查,通常簡稱為CRUD。

許可權的作用不是指明哪個使用者可以進行哪些操作,而是僅僅描述可進行的那些操作。

許可權級別

上面提到的許可權是針對某類資源(門、檔案、客戶記錄等等)上的操作(開啟、讀、刪等等)。在Shrio中,可以定義任何級別的許可權,下面是幾個常用的許可權級別:

  • 資源級別:應用最廣泛,最易使用的許可權。一個使用者可以編輯使用者資訊或開啟一扇門,這裡指定的是一類資源,而不是某資源特定的例項。
  • 例項級別:這類許可權是針對某類資源的例項。比如:某使用者可以編輯IBM公司的客戶記錄,或者可以開啟廚房的門。
  • 屬性級別:這類許可權針對某類資源或例項的屬性。比如:某使用者可以編輯IBM公司客戶的地址資訊。

預瞭解許可權更詳細資訊,請查閱許可權文件

角色定義

在授權範圍內,角色實際上就是許可權的集合,用來簡化使用者和許可權管理。這樣,使用者就可以分配給角色,而不是直接與許可權做關聯。進而解決複雜應用和較大使用者數量帶來的複雜性。比如銀行應用系統中可能有管理員和櫃員兩種角色。

讓我們瞭解下Shiro內建的兩種角色。

隱含角色

很多人把角色看做是隱含在應用中的一組許可權的集合,這是因為使用者擁有一個特定的角色,而這個特定的角色又與一組許可權相關聯或者應用中為這些許可權做檢查。一般程式碼中的角色檢查就反應了一種隱含的角色。擁有管理員角色,就可以檢視病人資訊,擁有櫃員角色就可以建立銀行賬戶。實際上,這些名字和軟體能完成的工作沒有相關性,很多人就是這樣去使用角色,當然這樣是最簡單的,但是它會給簡單的應用程式帶來很多的維護和管理上的問題。

顯式角色

顯式角色有明確的許可權與之關聯,所以顯式角色是一個許可權的集合。程式碼中的許可權檢查就反應了一種顯式角色。你可以檢視病人資訊是因為管理員角色擁有檢視病人資訊的許可權,你可以建立銀行賬戶因為櫃員角色擁有建立銀行賬戶的許可權。但是完成這些操作不是因為基於名稱的隱含角色,而是因為這種角色擁有該操作的許可權。

顯式角色給應用帶來的最大好處是易於管理和低維護成本。增加、修改、刪除角色時,根本不需要更改原始碼。當然,在Shiro中也可以在執行時動態新增、刪除、修改角色,而且授權檢查時會追加當前日期,這樣就不需要強制使用者登出再登入才能感知到新許可權的存在。

使用者定義

使用者是應用中的“who”,Shiro中使用者的概念是Subject例項。之所以使用Subject替代使用者概念,是因為使用者通常都是指人,而Shiro中Subject指的是任何與系統互動的“東西”,不管是人或是服務。

使用者通過與之關聯的角色或直接關聯的許可權可以執行應用中的某些操作。使用者可以檢視客戶資料,是因為使用者擁有檢視客戶資料的許可權,或者與之關聯的角色擁有檢視客戶資料的許可權。

預瞭解使用者(也叫Subject)更多資訊,請參閱Subject Document

最後,應用中自己實現的realm是用來與資料來源(RDBMS,LDAP等等)互動的,它將告知Shiro是否存在這樣的角色或者許可權。對授權模型如何工作,全權由我們自己控制。

如何使用Shiro在java中進行授權

Shiro中的授權有三種實現方式:

  • 程式設計實現:在Java程式碼中使用if,else結構實現授權檢查。
  • JDK註解:在Java方法上附加授權註解實現。
  • JSP/GSP標籤庫:基於角色和許可權控制jsp或gsp頁面的輸出。

程式設計實現授權

通過編寫java程式碼檢查許可權和角色是一種很傳統的處理授權方式。下面就是在Shiro中如何通過編碼方式檢查許可權與角色。

角色檢查

這個例子是在應用中通過編碼實現角色檢查功能。檢查使用者是否用管理員角色,如果有則顯示一個按鈕,如果沒有就不顯示。

首先要得到當前使用者,也就是Subject。然後將“administrator”作為引數傳遞給Subject的hasRole()方法,這個方法的返回值是true或false。

//獲取當前使用者
Subject currentUser =SecurityUtils.getSubject();
if (currentUser.hasRole(“administrator”)) {
    //顯示按鈕
} else {
    //隱藏按鈕
}

這樣一個簡單快捷的基於角色檢查的實現就完成了,但是它有一個很大的缺點,這個缺點還很隱晦。

想想隨後增加、刪除,或者修改角色會發生什麼?當然是必須修改原始碼以及所有與角色檢查相關的地方,來應對安全模型上的改變。而且每次都要停掉應用的服務,修改原始碼,測試通過,最終啟動服務。

這種方式適用於規模較小應用,但是對於規模較大的專案來說,這種方式只會成為專案生命週期中的主要問題,而且還會增加專案維護成本。

許可權檢查

下面是一個通過許可權實現安全檢查的示例。示例中檢查使用者是否有列印“laserjet3000n”的許可權,如果有則顯示列印按鈕,沒有就不顯示。這是一個例項級別的許可權示例,或者叫例項級別的授權示例。

首先還是要獲取當前使用者,也就是Subject,然後構造一個許可權(Permission)例項或者代表某資源上操作的例項。示例中例項是printerPermission,laserjet3000n是資源,資源上的操作是print。接下來將printerPermission作為引數傳遞給Subject的isPermitted()方法,它的返回值為true或false。

Subject currentUser = SecurityUtils.getSubject();
Permission printPermission = new PrinterPermission(“laserjet3000n”,“print”);
If (currentUser.isPermitted(printPermission)) {
    //do one thing (show the print button?)‏
} else {
    //don’t show the button?
}

基於字串的許可權檢查

也可以使用一個簡單的字串替代permission類來實現許可權檢查。

如果不想實現許可權介面,那麼只需要用一個字串作為引數。示例中將字串printer:print:LaserJet4400n 作為引數傳遞給isPermitted()。

String perm = “printer:print:laserjet4400n”;
if(currentUser.isPermitted(perm)){
    //show the print button?
} else {
    //don’t show the button?
}

只要自定義的Realm能夠解析許可權字串,可以用任意形式來定義。示例中使用Shiro可選的WildCardPermissions表示式。WildCardPermissions是一種功能強大,而且很直觀的表示式。

使用基於字串的許可權檢查可以實現與前面示例一樣的效果,這種方式的優點在於不在需要實現許可權介面,使用一個簡單的字串就可以構造一種許可權。它的不足之處是型別不安全。當想構造它能表達範圍之外的許可權時,也只能去實現許可權介面建立自己的許可權物件。

授權註解

如果不願意使用編碼的方式實現授權,那麼可以使用Java的註解來實現授權。Shiro提供了很多Java 註解enter link description here用來為方法新增註解。

開啟註解

使用Java註解前,需要先在應用中開啟對AOP的支援。不幸的是,很多AOP框架的存在,導致了沒有一個標準的在應用中開啟對AOP支援的方法。

對於AspectJ框架,參閱AspectJ 簡單應用

對於Spring框架,參閱Spring 整合文件

對於Guice框架,參閱Guice整合文件

許可權檢查

這個示例中,在呼叫openAccount方法前,檢查使用者是否有account:create許可權。如果有,方法則如期執行,否則丟擲異常。

與編碼方式做許可權檢查一樣,使用註解時既可以使用許可權物件,也可以使用簡單字串方法。

//如果呼叫者的角色中不具有賬戶建立的許可權,則會丟擲AuthorizationException異常
@RequiresPermissions(“account:create”)‏
public void openAccount( Account acct ) { 
    //create the account
}

角色檢查

這個示例中,呼叫openAccount方法前,檢查使用者是否有teller角色。如果有,方法則如期執行,否則丟擲異常。

//如果呼叫者不具有teller角色,則丟擲AuthorizationException異常。
@RequiresRoles( “teller” )
public void openAccount( Account acct ) { 
    //do something in here that only a teller
    //should do
}

授權JSP標籤庫

對於JSP/GSP的web應用,Shiro提供了標籤庫來實現授權。

示例中,通過user:manage許可權來控制前往使用者管理頁面的連結。如果使用者沒有user:manage許可權,則會給出友好的資訊提示。

首先需要將Shiro標籤庫載入到應用中,然後使用標籤檢查是否擁有user:manage許可權。檢查通過則會執行 標籤內部的程式碼。還可以使用標籤來檢查使用者不具有user:manage許可權,不具有許可權時想執行的程式碼放到標籤中即可。

<%@ taglib prefix=“shiro” uri=http://shiro.apache.org/tags %>
<html>
<body>
    <shiro:hasPermission name=“users:manage”>
        <a href=“manageUsers.jsp”>
            Click here to manage users
        </a>
    </shiro:hasPermission>
    <shiro:lacksPermission name=“users:manage”>
        No user management for you!
    </shiro:lacksPermission>
</body>
</html>

當然,還有很多標籤用於檢查角色和使用者資料與狀態。

想更多的瞭解JSP/GSP標籤的資訊,請參閱JSP標籤庫。想更多瞭解web整合方面資訊的,請參閱Web整合文件

原文連結:http://shiro.apache.org/java-authorization-guide.html

相關文章