參考博客:
https://blog.csdn.net/jiangtianjiao/article/details/87909065
https://www.iteye.com/blog/huangyunbin-1942509
我的需求:
今天在學設計模式,學到模板方法,看到Arrays.sort()方法里調用有用到這個類,不認識,
我是這樣做的:
百度百度研究下:
AccessController.doPrivileged在底層源碼中會出現,本文對它進行一個簡單介紹及如何使用的說明。
首先解釋一下幾個相關概念保護域
類被裝入jvm,為每個類指定一個保護域,保護域定義了授予一段特定代碼的所有權限,一個保護域對應一個策略policy.txt文件的一個或者多個grant子句,被裝入jvm的每一個類型僅屬於一個保護域。
那么一個類型如何被指派到保護域呢?
類裝載器知道自己裝載的所有類和接口的代碼庫和簽名者,它利用這些信息生成CodeSource對象,將CodeSource對象傳遞給當前policy對象(policy對象代表了一個從代碼來源到權限的全局映射,最終還是由類裝載器負責決定代碼執行時獲取什么樣權限)的getPermssions方法,得到PermissionCollection抽象類的子類實例,PermissionCollection包含所有Permission對象的引用,利用它創建的CodeSource和它從Policy對象得到的PermissionCollection,可以實例化一個新的保護域PretectDomain對象,然后傳遞給defineClass方法,來將這段代碼放入保護域內。
順便描述一下以下三個類加載器使用到方法
loadClass:調用findLoadedClass(String) 這個方法,查看這個Class是否已經被加載,如果沒有被加載,繼續往下走,查看父類加載器,遞歸調用loadClass(),如果父類加載器是null,說明是啟動類加載器,查找對應的Class,如果都沒有找到,就調用findClass,一般被重寫。
findClass:根據名稱或位置加載.class字節碼,然后使用defineClass,通常由子類去實現。
defineClass:解析定義.class字節流,返回class對象。
如下Friend和Friend$1是friend.jar的兩個class文件
訪問控制器
java.security.AccessController提供了一個默認的安全策略執行機制,它使用棧檢查來決定潛在不安全的操作是否被允許。
AccessController最核心方法是它的checkPermission靜態方法,該方法決定一個特定的操作是否被允許。允許則簡單返回,禁止則拋出AccessControlException異常。checkPermission自頂向下檢查棧幀,每個棧幀代表了當前線程調用的某個方法,每一個方法是在某個類中定義,每個類又屬於某個保護域,每個保護域包含一些權限,因此每個棧幀間接和一些權限相關,要遇到一個沒有權限幀就拋出異常。棧檢查可以通過使用doPrivileged方法來中斷,后續的棧幀對操作的資源不論是否有權限都無關。
implies()方法
表示當前Permission對象 (this) 是否暗含了指定 Permission 對象(permission) 的權限。
permission 子類必須實現此方法,因為它們是惟一能在 permission 對象上施加語義的類。
Java 中給出一個經典實現:BasicPermission,它使用了傳入的字符串作為權限的標志,並使用類似於相對路徑的辦法比較一個 Permission 是否暗含了另一個Permission 的權限。
import java.security.BasicPermission; import java.security.PermissionCollection; public class ImpliesTest { public ImpliesTest() { } public static void testImplies() { MyPermission usaBp = new MyPermission("usa.*"); //全美國 MyPermission chinaBp = new MyPermission("china.*"); //全中國 MyPermission hubeiBp = new MyPermission("china.hubei.*"); //全湖北省 MyPermission wuhanBp = new MyPermission("china.hubei.wuhan.*"); //全武漢市 MyPermission wuchangBp = new MyPermission("china.hubei.wuhan.wuchang.*"); //全武昌區 System.out.println(chinaBp.implies(usaBp)); //false全美國並不暗含全中國 System.out.println(hubeiBp.implies(wuchangBp)); //true全湖北暗含了全武昌 System.out.println(hubeiBp.implies(chinaBp)); //false全湖北並不暗含全中國 // Java 對於權限還給出一個權限集合類PermissionCollection,它是一組權限的並集。 // 對任意給定的Permission進行測試權限,只要被這個集合中的任意一個Permission 暗含即可。 // 需要注意的是,該集合中只能是同種類型的Permission。 PermissionCollection bpc = usaBp.newPermissionCollection(); bpc.add(chinaBp); System.out.println(bpc.implies(hubeiBp)); //true(全美國 | 全中國)暗含了全湖北 } public static void main(String[] args) { testImplies(); } } class MyPermission extends BasicPermission { private static final long serialVersionUID = 1L; public MyPermission(String name) { super(name); } } // 通過文件目錄讀權限測試implies方法 Permission file = new FilePermission("/tmp/f", "read"); Permission star= new FilePermission("/tmp/*", "read"); boolean sif = star.implies(file) // 輸出true boolean fis= file.implies(star) // 輸出false
棧檢查機制
假設有這樣一種情況:程序A想在/tmp目錄中新建一個文件,它沒有相應的權限,但是它引用了另外一個B.Jar包,剛好B有權限在/tmp目錄中新建文件,而B在新建文件的時候采用的是AccessController.doPrivileged方法進行的,這種情況下A就可以調用B的創建文件方法進行文件創建。
AccessController.doPrivileged中斷了棧檢查過程,使得后續原本沒有權限的代碼也可以正常執行,從而成功創建文件,如果不使用AccessController.doPrivileged,會一直進行棧檢查直到棧底位置,在程序A的棧幀(棧底)中會拋出權限異常,文件創建失敗。
示例參考:http://www.blogjava.net/Phrancol/articles/259069.html
public void doService() { // doFileOperation(); AccessController.doPrivileged(new PrivilegedAction() { public Object run() { doFileOperation(); return null; } }); }
總結:
在某一個線程的調用棧中,當 AccessController的checkPermission方法被最近的調用程序調用時,對於程序要求的所有訪問權限,ACC決定是否授權的基本算法如下:
1. 如果調用鏈中的某個調用程序沒有所需的權限,將拋出AccessControlException。
2. 若是滿足以下情況即被授予權限:
a.調用程序訪問另一個有該權限域里程序的方法,並且此方法標記為有訪問特權。
b.調用程序所調用(直接或間接)的后續對象都有上述權限。