Java中如何使用AccessController.doPrivileged防止文件被删除
问题原因及解决方案
核心原因
- Java的权限校验体系(包括
FilePermission、AccessController)默认不生效,必须先开启JVM安全管理器才会执行权限校验。你原来的代码没开安全管理器,所以所有权限配置都没有作用,只要操作系统层面进程有文件删除权限,就可以直接删除文件。 - 删除文件对应的
FilePermission动作是delete,你如果要禁止删除,就不要给该权限。另外三参数重载的AccessController.doPrivileged作用是限制本次特权操作的最大权限为传入权限和当前上下文权限的交集,刚好可以用来限制操作范围。
调整步骤
1. 启用JVM安全管理器
不同JDK版本的开启方式不同:
- JDK 8及更早版本:启动程序时添加JVM参数
-Djava.security.manager - JDK 9~17版本:安全管理器被标记为废弃,需要添加参数
-Djava.security.manager=allow才能启用 - JDK 18及以上版本:安全管理器被完全移除,无法使用该方案做权限控制
2. 调整代码权限配置
你现在的代码如果开了安全管理器,首先createNewFile就会失败,因为创建文件需要write权限。如果你的需求是允许创建、读取文件,禁止删除,调整后的代码如下:
import java.io.File; import java.io.FilePermission; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.AccessControlException; public class ReadOnlyFile { public static void readOnly() throws Exception { final File f = new File("/tmp/secure.txt"); // 创建文件时授予write、read权限 final boolean created = AccessController.doPrivileged((PrivilegedAction<Boolean>) f::createNewFile, null, new FilePermission(f.getPath(), "read,write")); System.out.println(f.getAbsolutePath() + " has been created: " + created); try { // 删除操作只授予read权限,没有delete权限 final boolean deleted = AccessController.doPrivileged((PrivilegedAction<Boolean>) f::delete, null, new FilePermission(f.getPath(), "read")); System.out.println(f.getAbsolutePath() + " has been deleted: " + deleted); } catch (AccessControlException e) { System.out.println("删除操作被权限校验拦截,无法删除文件"); } } public static void main(String[] args) throws Exception { readOnly(); } }
3. 可选:配置全局安全策略
如果你需要全局限制该文件的删除权限,而不是仅限制单次操作,可以修改JDK的安全策略文件(默认路径为jre/lib/security/java.policy),添加对应的权限配置,禁止所有代码获取该文件的delete权限。
注意事项
- 该方案只能限制Java代码层面的文件操作,无法限制操作系统层面的其他进程、或者Java代码通过JNI调用本地方法进行的文件删除操作。
- 由于高版本JDK已经移除了安全管理器,长期使用的话更建议直接通过操作系统的文件权限配置(比如Linux下给文件设置
chmod 444、设置不可修改位chattr +i)来实现禁止删除的效果,兼容性和安全性更高。
内容的提问来源于stack exchange,提问作者user657009
相关产品推荐
相关产品推荐

