一个例子理解AccessController.doPrivileged()

本文通过示例解析了Java安全模型中的AccessController.doPrivileged()方法如何工作,包括其在不同保护域间的权限检查流程及应用技巧。
部署运行你感兴趣的模型镜像

示例中需要在eclipse中创建2个project:ServiceCentre和TestService

java.policy

grant codeBase  " file:/D:/Workspaces/ExchangeConnect_V2_Trunk_Maven_workspace/ServiceCentre/bin/* "   {
    permission java.io.FilePermission 
"c:/TestService-1.0.jar""read";
    permission java.lang.RuntimePermission 
"createClassLoader";
}
;

grant codeBase 
" file:/c:/TestService-1.0.jar "   {
    permission java.io.FilePermission 
"C:/text.txt""read";
}
;




Project - ServiceCentre

package  test;

import  java.lang.reflect.Method;
import  java.net.URL;
import  java.net.URLClassLoader;

/**
 * 
@author Donf Yang
 
*/

public   class  ServiceCentreMain  {

    
public void loadService() {
        URL[] urls;
        
try {
            urls 
= new URL[] new URL("file:c:/TestService-1.0.jar") };
            URLClassLoader ll 
= new URLClassLoader(urls);
            
final Class a = ll.loadClass("test.TestService");
            Object o 
= a.newInstance();
            Method m 
= a.getMethod("doService"null);
            m.invoke(o, 
null);

        }
 catch (Exception e) {
            e.printStackTrace();
        }

    }


    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        ServiceCentreMain s 
= new ServiceCentreMain();
        s.loadService();
    }


}


 

Project - TestService
将TestService打包,放到C盘
package  test;

import  java.io.FilePermission;
import  java.security.AccessController;
import  java.security.Permission;

/**
 * 
@author Donf Yang
 * 
 
*/

public   class  TestService  {

    
public void doService() {
        
        doFileOperation();

    }


    
private void doFileOperation() {
        Permission perm 
= new FilePermission("C:/text.txt""read");
        AccessController.checkPermission(perm);
        System.out.println(
"TestService has permission");
    }


}

运行这个例子的时候,会出现权限错误,把doService()修改一下,就可以顺利通过
public   void  doService()  {

        
// doFileOperation();

        AccessController.doPrivileged(
new PrivilegedAction() {
            
public Object run() {
                doFileOperation();
                
return null;
            }

        }
);
    }

在这个例子中AccessControlContext的stack顺序为
2.  file:/D:/Workspaces/ExchangeConnect_V2_Trunk_Maven_workspace/ServiceCentre/bin/*
1 . file:/c:/TestService-1.0.jar

2没有权限,1有权限,使用doPrivileged后,不检查2



看一下java.security.AccessController的JavaDoc:

A caller can be marked as being  " privileged "  (see doPrivileged and below). When making access control decisions, the checkPermission method stops checking  if  it reaches a caller that was marked as  " privileged "  via a doPrivileged call without a context argument (see below  for  information about a context argument). If that caller ' s domain has the specified permission, no further checking is done and checkPermission returns quietly, indicating that the requested access is allowed. If that domain does not have the specified permission, an exception is thrown, as usual. 

其中提到的no further checking is done的意思是指stack中的checking

加入一个TestService2,文件操作在1,stack为(1,2,3为checking顺序)
3 . file:/D:/Workspaces/ExchangeConnect_V2_Trunk_Maven_workspace/ServiceCentre/bin/*
2 . file:/c:/TestService-1.0.jar
1.  file:/c:/TestService2-1.0.jar
 checking顺序为  1->2->3
如果doPrivileged是在2中调用,那么1,2需要具有权限,3不再进行检查
如果doPrivileged是在1中调用,那么1需要具有权限,2,3不再进行检查


总结:
1.  这里容易理解错误的地方是checking顺序,例如一个调用链 MethodA->MethodB->MethodC(这里的3个方法需要在3个不同的ProtectionDomain中),doPrivileged在MethodB中,很容易理解成检查A,B而不检查C,实际上stack中检查顺序为C->B->A,也就是检查C,B而不检查A

2. ServiceCentre不需要太多权限,而Service就需要使用doPrivileged来避免受到ServiceCentre的权限限制(如果service有足够的权限),Equinox中有很多这样的例子(Equinox扮演Service的角色)。

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think> 我们需要回答的是:在Java中,`AccessController.doPrivileged` 被弃用后,用什么代替? 实际上,`AccessController.doPrivileged` 并没有完全被弃用,但是在模块化系统(Java 9引入)之后,安全模型有所改变。 在Java 9及更高版本中,`AccessController` 和 `doPrivileged` 方法仍然存在,但官方推荐使用新的 `java.security.PrivilegedAction` 和 `java.security.PrivilegedExceptionAction` 接口的替代方式,以及使用 `java.security.AccessController` 的上下文。 然而,更值得注意的是,Java平台模块系统(JPMS)引入了新的权限模型,推荐使用模块化和权限声明,而不是直接使用`doPrivileged`。但如果你需要在特权块中执行代码,仍然可以使用`AccessController.doPrivileged`,不过它没有被标记为弃用。 但是,在Java 9中,有一个新的方法被引入:`AccessController.doPrivileged` 有一个新的变体,它接受一个 `AccessControlContext` 和一个可选的 `Permission` 集合。同时,为了与模块系统集成,建议使用`java.security.Policy`的新API。 所以,严格来说,`AccessController.doPrivileged` 并没有被弃用。但是,如果你在文档或某些上下文中看到弃用的说法,可能是误解,或者是指特定的用法。 不过,在模块化应用程序中,权限控制更倾向于使用模块描述符中声明的权限,而不是在代码中执行特权块。如果确实需要执行特权操作,可以继续使用`AccessController.doPrivileged`。 但是,我们也可以使用`java.security.PrivilegedAction`的Lambda表达式版本,因为它是函数式接口。 例如,在Java 8及以后,可以这样写: ```java AccessController.doPrivileged((PrivilegedAction<Void>) () -> { // 执行需要特权的操作 return null; }); ``` 或者,如果操作有检查异常,则使用`PrivilegedExceptionAction`: ```java try { AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> { // 可能会抛出检查异常的操作 return null; }); } catch (PrivilegedActionException e) { // 处理异常 } ``` 总结:`AccessController.doPrivileged` 方法并没有被弃用,仍然可以正常使用。但在模块化系统中,权限管理的方式有所改变,建议通过模块描述符(module-info.java)来声明权限。 因此,回答用户的问题:`AccessController.doPrivileged` 并没有被弃用,所以不需要代替。但是,如果用户是在模块化系统中,应该考虑使用模块权限声明来管理权限,并尽量减少使用`doPrivileged`。 然而,如果用户看到弃用警告,可能是针对特定的方法签名。在Java 17中,`AccessController`类仍然存在,并且`doPrivileged`方法也没有标记为弃用。所以,用户可能遇到了错误的信息。 但是,为了完整起见,我们注意到在Java的更新中,安全API可能会有调整。目前,没有官方推荐的直接替代品,因为该方法仍然在使用。 因此,我们给出的解决方案是:继续使用`AccessController.doPrivileged`,但遵循模块化系统的安全实践。 下面是一个使用示例: </think> 在 Java 安全模型中,`AccessController.doPrivileged` 并没有被正式弃用(截至 Java 17),但官方推荐使用更现代的权限控制方式。以下是替代方案和最佳实践: ### 1. 使用 `ProtectionDomain` + `Permission` 的声明式控制(推荐) ```java import java.security.*; public class SecureService { // 在模块描述文件中声明所需权限(module-info.java) module your.module { requires java.security; provides your.service.InterfaceName with your.service.SecureService; } public void sensitiveOperation() { // 声明式权限检查(替代显式doPrivileged) SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("accessDeclaredMembers")); } // 执行敏感操作 System.out.println("Sensitive operation performed"); } } ``` **原理**:通过模块系统声明权限边界,依赖 JVM 的自动权限检查机制,避免显式特权代码块。 --- ### 2. 使用 `Principal` + `Policy` 的上下文控制 ```java import javax.security.auth.Subject; import java.security.PrivilegedAction; public class SecureExecutor { public void executeWithContext() { Subject subject = ... // 从安全上下文获取 Subject.doAsPrivileged(subject, (PrivilegedAction<Void>) () -> { // 在主体上下文中执行 System.out.println("Action with subject's permissions"); return null; }, null); // 第三个参数为 AccessControlContext } } ``` **原理**:通过 JAAS 框架将操作绑定到特定安全主体,利用 `Subject.doAsPrivileged` 实现上下文隔离。 --- ### 3. 使用模块化沙箱(Java 9+) ```java // 在模块描述文件中声明沙箱权限 module untrusted.module { requires java.base; // 显式导出可访问的包 exports com.untrusted.api; } ``` **配置**:使用 JVM 参数控制模块权限: ```bash --add-opens=target.module/package=untrusted.module ``` --- ### 弃用警告说明 虽然核心 `AccessController.doPrivileged` 方法未被弃用,但相关模式存在风险: 1. **过度特权**:可能意外扩大权限范围 2. **上下文污染**:特权可能泄漏到非预期代码路径 3. **模块兼容**:与 JPMS 模块系统的细粒度控制冲突 --- ### 迁移建议 1. **重构特权代码**: ```java // 旧方式(不推荐) AccessController.doPrivileged((PrivilegedAction) () -> { return sensitiveResource.access(); }); // 新方式:分解为独立服务 public class ResourceService { @RequiresRuntimePermission("accessSensitiveResource") public Resource access() { ... } } ``` 2. **使用注解驱动权限**: ```java @RequiresPermission(permission = "readFile", resource = "/confidential") public void readConfidentialFile() { ... } ``` ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值