前面一節我們做了一個簡單的實驗來說明什麼是策略文件在文章的最後也順帶的講了一下什麼是策略還有策略的作用
為了引出另外一個很重要的概念ProtectionDomain(保護域)所以我們還是要先來回顧一下什麼是策略
首先什麼是策略今天的東西純粹是比較概念的當然如果你讀過筆記九今天的東西就真的是soso
策略與策略文件
java對應用程序的訪問控制策略是由抽象類javasecurityPolicy的一個子類的單例所表示任何時候每個應用程序實際上只有一個Policy對象Policy對象對應著策略文件類裝載器利用這個Policy對象來幫助他們決定在把一段代碼導入虛擬機時應該給予什麼權限
上面那段話告訴我們一個應用程序對應一個策略對象一個策略對象對應一個策略文件
那麼策略文件除了對我們筆記九中一個文件夾下的所有文件起限制作用外還能對什麼主體起作用呢?先來看看下面的策略文件myPolicytxt
keystore ijvmkeys
grant signedby friend {
permission javaioFilePermission d:/testPolicytxt readwrite;
};
grant signedby stranger {
permission javaioFilePermission d:/testPolicytxt readwrite;
};
grant codeBase file:D:/workspace/TestPolicy/bin/* {
permission javaioFilePermission d:/testPolicytxt readwrite;
};
簡單的解讀一下
第一行keystore ijvmkeys這一行的意思密鑰對存放在當前目錄一個叫ijvmkeys的文件裡(記得筆記八做過的jar包簽名實驗嗎)
第二行grant signedby friendgrant是授權的意思這一行的意思是給一個被friend的密鑰對簽名的文件授權
第三行permission javaioFilePermission d:/testPolicytxt readwrite;這行的意思是對於d:/testPolicytxt賦予讀寫的權限
倒數第三行grant codeBase file:D:/workspace/TestPolicy/bin/* 這一句我們筆記九的時候見過就是對D:/workspace/TestPolicy/bin/*下的所有文件賦予權限
重點一到這裡我們應該可以知道策略文件可以給一系列被簽名的代碼庫(friendstranger都是代碼庫)授權也可以給一個代碼來源(一個具體的路徑或者說url就是一個代碼來源)授權
重點二策略文件不僅可以存儲在文件中(後綴名是什麼不重要)還可以存放在數據庫裡
到了這裡我們對策略有一個比較完整的概念了但是你有沒有這麼一個疑問前面我們總說一個應用程序對應一個策略單例一個策略單例對應一個策略文件它到底怎麼對應的?下面我們就來探究一下
在探究之前我們先引入一個新的概念叫保護域(ProtectionDomain)在筆記三的時候我們提到過類裝載器將class文件load內存的時候會將它放置到一個保護域中是滴今天我就來說說什麼是保護域
什麼是保護域
當類裝載器將類型裝入Java虛擬機時它們將為每個類型指派一個保護域保護域定義了授予一段特定代碼的所有權限(一個保護域對應策略文件中的一個或多個Grant子句)裝載入Java虛擬機的每一個類型都屬於一個且僅屬於一個保護域
類裝載器知道它裝載的所有類或接口的代碼庫和簽名者它利用這些信息來創建一個CodeSource對象它將這個CodeSource對象傳遞個當前Policy對象的getPermissions()方法得到這個抽象類javasecurityPermissionCollection的子類實例這個PermissinCollection包含了到所有Permission對象的引用(這些Permission對象由當前策略授予指定代碼來源)利用它創建的CodeSource和它沖Policy對象得到的PermissionCollection它可以實例化一個新的ProtectDomain對象它通過將合適的ProtectionDomain對象傳遞給defineClass()方法來將這段代碼放到一個保護域中
如果你對上面這段話理解不了看下面這個圖
好了看完上面的這整個過程之後你是否已經理解什麼是保護域了
下面我們在整理一下內容概念有點多一個一個的來
codeSource:代碼源這個是類裝載器生成的javasecurityCodeSource的一個對象classLoader通過讀取class文件jar包得知誰為這個類簽過名(可以有過個簽名者關於簽名請查看筆記七和八)而封裝成一個簽名者數組賦給codeSource對象的signers成員通過這個類的來源(可能來自一個本地的url或者一個網絡的ur對應了grant筆記九裡myPollicy裡的friend或者file::…l)賦給codeSource的location成員還有這個類的公鑰證書賦給codeSource的certs成員(通常一個jar是能夠被多個團體或者機構擔保的也就是我們說的認證在java的默認安全管理器還有訪問控制體系結構都只能對證書起作用而不能對赤裸的公鑰起作用而實際上我們用keytool生成密鑰對時同時會生成一個自簽名證書所以keytool生成的密鑰對並不是赤裸的)如果你有疑問我們看一下jdk裡的代碼
public class CodeSource implements javaioSerializable {
private static final long serialVersionUID = L;
/**
* The code location
*
* @serial
*/
private URL location;//本地代碼庫
/*
* The code signers
*/
private transient CodeSigner[] signers = null;//簽名者
/*
* The code signers Certificate chains are concatenated
*/
private transient javasecuritycertCertificate certs[] = null;//證書
Policy:策略就是用來讀取策略文件的一個單例對象通過傳入的CodeSource對象(由於codeSource對象裡包含了簽名者和代碼來源)所以他通過讀取grant段取出一個個的Perssiom然後返回一個PerssiomCollection這個類裡有一個很重要的成員變量
// Cache mapping ProtectionDomain to PermissionCollection
private WeakHashMap pdMapping;
這個成員為什麼重要我們來看一個方法
private static void initPolicy (final Policy p) {
……
if (policyDomaingetCodeSource() != null) {
……
synchronized (ppdMapping) {
// cache of pd to permissions
ppdMappingput(policyDomain policyPerms)
}
}
return;
}
我們主要看關鍵代碼這個pdMapping就是把保護域對象當做key將權限集合當做value存在在了這個map裡所以我們說一個保護域對應多個策略文件的grant子句的permission
ProtectionDomain:保護域前面我們已經介紹過了他就是用來容納class文件還有perssiomcodeSource的一個對象如果你對此還有什麼疑問我們也看看它的代碼來驗證一下我們的結論
public class ProtectionDomain {
/* CodeSource */
private CodeSource codesource ;//代碼源
/* ClassLoader the protection domain was consed from */
private ClassLoader classloader;//類裝載器
/* Principals runningas within this protection domain */
private Principal[] principals;
/* the rights this protection domain is granted */
private PermissionCollection permissions;//權限集合
Permission:權限這個對應了我們筆記九裡的grant子句裡的一個permission它的結構也很簡單權限名和動作就好像我們筆記九裡的javaioFilePermission是一個權限名
而動作則是read和write在Permission中它對應一個字符串
現在我們用一張圖來把上面幾個概念串聯起來
到這裡我們已經有一條比較完整的思路了從筆記四到這一節的筆記十我們所要說的都只有一件事情類裝載器在裝載類的時候(或者執行類)會調用安全管理器安全管理器則通過判斷策略來判斷我們是不是允許加載這個類或者執行某些操作筆記某個文件的讀寫啊之類的(這個在筆記九的時候我們已經做過實驗了)
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26831.html