自定义策略文件的Java SecurityManager未按预期工作
我正在学习Java SecurityManager的工作机制,编写了测试代码验证,但始终抛出异常。
测试代码
public class FilePermissionChecker2 { public static void main(String[] args) { String filePath = "c:\\file.txt"; Permission perm = new FilePermission(filePath, "read,write"); PermissionCollection perms = perm.newPermissionCollection(); perms.add(perm); boolean hasPermission = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { // 检查文件权限 File file = new File(filePath); if (file.exists() && file.canRead() && file.canWrite()) { return true; } else { return false; } } }, new AccessControlContext( new ProtectionDomain[]{ new ProtectionDomain(null, perms) } )); if (hasPermission) { System.out.println("拥有必要的文件权限。"); } else { System.out.println("没有必要的文件权限。"); } } }
自定义策略文件
grant { permission java.io.FilePermission "c:\\file.txt", "read, write"; };
VM参数设置
-Djava.security.manager -Djava.security.policy=...pathToPolicy...\policy\custom.policy
异常信息
Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "c:\file.txt" "read")
我预期SecurityManager会基于自定义策略和代码中的权限取交集进行检查,但实际未生效,请问问题出在哪里?
已尝试操作:
- 调整自定义策略的多种组合
- 调整FilePermissions的多种组合
问题分析与解决方案
策略文件路径验证
确保VM参数中-Djava.security.policy的路径正确:- Windows下路径需使用正斜杠(
/)或双反斜杠(\\),如果路径包含空格,需要用引号包裹,例如:-Djava.security.policy="C:\\Program Files\\policy\\custom.policy" - 优先使用绝对路径,避免相对路径因IntelliJ工作目录不一致导致的加载失败。
- Windows下路径需使用正斜杠(
JDK版本兼容性
JDK 17及以上版本中SecurityManager已被废弃,虽然通过-Djava.security.manager仍可启用,但存在兼容性问题。建议切换到JDK 8或11进行测试。代码逻辑调整
原代码通过File.exists()/canRead()/canWrite()触发权限检查,这类方法可能隐含额外的系统检查。建议直接通过AccessController.checkPermission验证权限,逻辑更明确:@Override public Boolean run() { try { AccessController.checkPermission(perm); // 若权限通过,再执行文件操作 File file = new File(filePath); return file.exists() && file.canRead() && file.canWrite(); } catch (AccessControlException e) { return false; } }权限集合有效性验证
在代码中添加日志,确认PermissionCollection是否正确包含权限:System.out.println("权限集合内容:" + perms.toString());输出应包含
(java.io.FilePermission c:\file.txt read,write),否则说明权限添加逻辑有误。启用权限调试
添加VM参数-Djava.security.debug=access,查看详细的权限检查日志,可明确是哪个ProtectionDomain拒绝了权限,以及检查的具体规则。
内容的提问来源于stack exchange,提问作者Štefan Starosta

