简介

安全管理器是 Java 沙箱的基本组件之一,管理核心 API 调用系统接口时的安全策略

Java 应用程序请求 Java API 完成某个操作时,API 会向安全管理器询问是否可以执行,安全 管理器若不希望执行该操作,会抛一个异常给 API

例子

如下示例代码中,Java 尝试读取系统中的文件:

public static void main(String[] args) {
    String s;
    try {
        FileReader fr = new FileReader(new File("E:\\test.txt"));
        BufferedReader br = new BufferedReader(fr);
        while ((s = br.readLine()) != null)
            System.out.println(s);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在创建 FileReader 对象的时候会先根据 File 对象创建 FileInputStream 实例,源码如下:

public FileInputStream(File file) throws FileNotFoundException {
    String name = (file != null ? file.getPath() : null);
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkRead(name);
    }
    if (name == null) {
        throw new NullPointerException();
    }
    if (file.isInvalid()) {
        throw new FileNotFoundException("Invalid file path");
    }
    fd = new FileDescriptor();
    fd.attach(this);
    path = name;
    open(name);
}

在读取文件字节流之前,首先通过 System.getSecurityManager() 获取当前系统的安全管 理器,然后调用其 checkRead 方法检查是否具有读权限,如果有权限就继续读取,否则抛 出异常

checkRead 方法的相关代码如下:

public void checkRead(String file) {
    checkPermission(new FilePermission(file,SecurityConstants.FILE_READ_ACTION));
}
 
public void checkPermission(Permission perm) {
    java.security.AccessController.checkPermission(perm);
}

可以看到,SecurityManager 对访问文件的校验,最终是交由访问控制器 (AccessController)实现的,若校验失败则抛出 AccessControlException 异常

一般情况下,安全管理器默认是没有被安装的,getSecurityManager 方法将返回 null,可 以通过 setSecurityManager 方法显式启用,或者启动 JVM 时使用 -Djava.security.manager 选项