怎樣淺談Java訪問控制機制,針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
創(chuàng)新互聯(lián)建站堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的長島網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
Java 訪問控制機制的原理是:在某些策略配置文件中預(yù)定義好某些代碼對某些資源具有某些操作權(quán)限,當(dāng)某些代碼以某個權(quán)限訪問某個資源的時候,如果對該資源預(yù)指定的權(quán)限中沒有該權(quán)限,則禁止訪問,否則可以訪問。
上面一段話讀起來比較晦澀,下面先以數(shù)據(jù)庫用戶和數(shù)據(jù)表為例來說明。
指定某些代碼對某些資源具有某些操作權(quán)限
某些代碼:用戶 Admin, X
某些資源:數(shù)據(jù)庫表 User
操作權(quán)限:用戶 Admin(某些代碼)對 User 表(某些資源) 具有 CRUD 權(quán)限
用戶 X(某些代碼)對 User 表(某些資源) 具有 R 權(quán)限
某些代碼以某個權(quán)限訪問某個資源
用戶 X(某些代碼)查詢(某個權(quán)限) User 表(某些資源),因為預(yù)定義中用戶 X 對 User 表是有查詢權(quán)限的,所以檢查通過
用戶 X(某些代碼)刪除(某個權(quán)限) User 表(某些資源) 中某條數(shù)據(jù),因為預(yù)定義中用戶 X 對 User 表只有查詢權(quán)限,沒有刪除權(quán)限的,所以檢查不通過
在 Java 中,道理也是一樣的,只是 Java 中某個類相當(dāng)于上面的某個用戶,如 ClassA 相當(dāng)于用戶 Admin, ClassB 相當(dāng)于用戶 X。 但是在 Java 中情況稍微復(fù)雜一點,比如 ClassB 可以調(diào)用 ClassA 的方法,那么這時候,權(quán)限將如何檢查呢?還是以例子來說明。
指定某些代碼對某些資源具有某些操作權(quán)限
某些代碼:用戶 ClassA, ClassB
某些資源:某個配置文件 x.properties
操作權(quán)限:ClassA(某些代碼)對 x.properties(某些資源) 具有讀寫權(quán)限
ClassB(某些代碼)對 x.properties(某些資源) 具有讀權(quán)限
某些代碼以某個權(quán)限訪問某個資源
ClassA(某些代碼)讀或?qū)?某個權(quán)限) 配置文件x.properties(某些資源),因為預(yù)定義中ClassA 對 x.properties是有讀和寫權(quán)限的,所以檢查通過
ClassB(某些代碼)讀(某個權(quán)限) 配置文件x.properties(某些資源),因為預(yù)定義中ClassB對 x.properties是有讀權(quán)限的,所以檢查通過
ClassB(某些代碼)寫(某個權(quán)限) 配置文件x.properties(某些資源),因為預(yù)定義中ClassB對 x.properties是沒有寫權(quán)限的,所以檢查不通過
Class B 調(diào)用 ClassA 的寫 x.properties 文件方法,是什么檢查過程呢?
在 Java 中,不管有幾個類的反復(fù)調(diào)用,最終都是以某個權(quán)限操作某個資源,如這里是 Class B 調(diào)用 ClassA,其最終操作權(quán)限是以寫的權(quán)限去操作 x.properties 文件。那么 Java 就會對反復(fù)調(diào)用過程中的所有類進(jìn)行檢查,看它們對 x.properties 文件是否有寫權(quán)限,如果都有則通過,只要任何一個類沒有該權(quán)限,則不通過。
其中檢查的過程與調(diào)用過程是互為逆向的。如在上例中,ClassB 調(diào)用 ClassA 的去寫 x.properties 文件,那么 JVM 就會先檢查 ClassA 對 x.properties 文件是否有寫權(quán)限,因為預(yù)定義中有,所以 ClassA 通過。接下來檢查 ClassB,因為預(yù)定義中,ClassB對 x.properties 文件沒有寫 權(quán)限,所以檢查不通過,本次操作失敗。
在 Java 訪問控制機制中,主要有以下幾個類:
SecurityManager
AccessController
AccessControlContext
ProtectionDomain
PermissionCollection
Permission
Policy
SecurityManager/ AccessController
訪問控制的入口類。在 Java 中,訪問控制默認(rèn)是關(guān)閉的。
AccessControlContext
類的調(diào)用過程上下文。它以棧的形式保存類的調(diào)用過程,如在上面例子中,ClassB 調(diào)用 ClassA,那么 AccessControlContext 的棧底是 ClassB,棧頂是 ClassA,如果 ClassA 再調(diào)用 ClassC,那么 ClassC 在壓入棧,棧頂變成了 ClassC
ProtectionDomain
這是一個關(guān)鍵的類。它定義了“某些代碼對某些資源具有某些操作權(quán)限”,亦即那個目錄下的代碼對那些資源有哪些操作權(quán)限。它有三個屬性:
某些代碼
一般是指某個目錄下的所有代碼,如 “JRE_HOEM/lib/ext”在 Java 中表示為 CodeBase
某些資源
比如 conf 目錄下的文件,在 Java 中表現(xiàn)為某個文件(夾)路徑 BasePath
某些權(quán)限
是指某些代碼對對某些資源操作權(quán)限的集合,比如讀權(quán)限、寫權(quán)限,在 Java 中表現(xiàn)為 PermissionCollection 類。
PermissionCollection
權(quán)限的集合類。如文件讀權(quán)限、文件寫權(quán)限的集合:
FilePermission(file,SecurityConstants.FILE_WRITE_ACTION)
FilePermission(file,SecurityConstants.FILE_READ_ACTION)
Permission
某個具體的權(quán)限。如文件讀權(quán)限 FilePermission(file,SecurityConstants.FILE_WRITE_ACTION)
Policy
“指定某些代碼對某些資源具有某些操作權(quán)限”的策略定義在策略文件中,Policy 負(fù)責(zé)從配置文件中讀取這些策略,并根據(jù)策略文件構(gòu)建 ProtectionDomain。JVM 中只有一個 Policy 對象。
“某些代碼對某些資源具有某些操作權(quán)限”建立過程
在 Java 中,每個類都有一個 ProtectionDomain 的一個引用,因為每個類都屬于某個特定的目錄下,這樣就可以知道某個類對某些資源有哪些操作權(quán)限了。下面看每個類與 ProtectionDomain 建立關(guān)系的過程:
當(dāng) ClassLoader 去加載一個 class 的時候,它會把這個類及授給這個類的權(quán)限集封裝到“java.security.ProtectionDomain”中,其中這些權(quán)限是通過 ClassLoader并根據(jù)策略文件進(jìn)行分配的。
1) 找到類字節(jié)碼的加載 URL
2) 如果這個類是從包 java.* 中加載的,那就把該類與內(nèi)在的 System ProtectionDomain 關(guān)聯(lián),其中 System ProtectionDomain 是具有全部權(quán)限(AllPermission)的。如果該類不是從包 java.* 中加載的,則繼續(xù)
3) 如果該類要關(guān)聯(lián)的 ProtectionDomain 以及存在,則直接添加它們之間引用關(guān)系即可,否則繼續(xù)
4) 創(chuàng)建一個 CodeSource 對象,里面封裝了類字節(jié)碼的加載路徑
5) 創(chuàng)建一個 PermissionCollection 對象,并把策略文件中賦給 CodeSource 的權(quán)限封裝到該 PC 對象中
6) 創(chuàng)建一個 ProtectionDomain,里面封裝了 CodeSource 和 PermissionCollection 對象,即那些代碼對那些資源有那些操作權(quán)限:ProtectionDomain = new ProtectionDomain(CodeSource,PermissionCollection)
7) 把剛加載的 class 類與當(dāng)前的 ProtectionDomain 關(guān)聯(lián)
各個類之間引用調(diào)用關(guān)系這里不闡述,下面繼續(xù)看例子:
現(xiàn)在假設(shè)有如下代碼:${user.dir}/testA/ClassA ${user.dir}/testB/ClassB
有如下資源:${user.dir}/conf/x.properties
加入在 Java 策略文件中添加如下策略:
grant codeBase "file:${user.dir}/testA/*" {
permission java.io.FilePermission "${user.dir}/conf *", "read";
permission java.io.FilePermission "${user.dir}/conf *", "write";
};
grant codeBase "file:${user.dir}/testB/*" {
permission java.io.FilePermission "${user.dir}/conf *", "read";
};
上面有提到,在Java 中每個 Class都保存有 ProtectionDomain的引用,這里 ClassA 和 ClassB 的 ProtectionDomain 模型如下:
下面假設(shè) ClassB 調(diào)用 ClassA 的去寫 x.poperties 文件,那么 AccessControlContext 和 PermissionCollection 對應(yīng)模型是這樣的:
當(dāng) AccessController.checkPermission 開始檢查權(quán)限時,它知道要本次要檢查的權(quán)限是 FilePermission(“x.properties”, “write”),即對 “x.properties”的寫權(quán)限。于是它先獲取調(diào)用過程上下文中所有類(main(JVM)-->ClassB-->ClassA-->FileOutputStream-->AccessController)的 ProtectedDomain 找出來:
JVM 從 mian 執(zhí)行的,它的 ProtectedDomain 是 SystemDomain
ClassA 的 ProtectedDomain 是 ProtectedDomainA
ClassB 的 ProtectedDomain 是 ProtectedDomainB
FileInputStream 和 AccessController 的 ProtectedDomain 是 SystemDomain
把訪問上下文的 ProtectedDomain 都找出來后,就逐個檢查每個 ProtectedDomain 是否有 FilePermission(“x.properties”, “write”) 權(quán)限。因為在 Java 訪問控制機制中,它要確保每個調(diào)用的類都有該權(quán)限才能通過檢查。
于是,開始做下面檢查:
1) AccessController-->SystemDomain : Java 內(nèi)部代碼保護(hù)域,具有所有操作權(quán)限,檢查通過
2) FileInputStream-->SystemDomain : Java 內(nèi)部代碼保護(hù)域,具有所有操作權(quán)限,檢查通過
3) ClassA-->ProtectedDomainA: 在上面的 ProtectedDomainA 模型中,我們知道它是有 FilePermission(“x.properties”, “write”) 權(quán)限的,檢查通過
4) ClassB-->ProtectedDomainB: 在上面的 ProtectedDomainB 模型中,我們知道它沒有 FilePermission(“x.properties”, “write”) 權(quán)限的,檢查不通過
關(guān)于怎樣淺談Java訪問控制機制問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。