13.3.2 访问控制权限

在声明了程序在运行中应该满足的访问控制权限之后,需要在代码中显式地应用这些要求。比如某个方法只有具有了特定权限的主体才能调用,在该方法被执行之前,需要先检查当前调用上下文,判断主体是否具备这样的权限。如果没有权限,方法应该直接抛出相关的java.security.AccessControlException异常。这些访问控制权限与具体的程序相关,需要由开发人员在代码中显式进行处理。

访问控制权限的检查由java.lang.SecurityManager类和java.security.AccessController类来共同完成。SecurityManager类是Java早期版本中的实现方式,其中包含一些以“check”作为前缀的方法,通过这些方法可以进行相应的权限检查。比如checkRead方法可以检查是否具有读取给定路径对应的文件的权限。对于程序本身的权限,可以通过继承SecurityManager类的方式来添加相应的检查方法。Java标准库中的很多方法中都添加了使用SecurityManager类进行访问控制权限检查的代码。

对于Java Applet来说,SecurityManager类所做的检查总是启用的,这是由Applet本身的不安全特性所决定的。对于在本地虚拟机上直接运行的程序,SecurityManager类所做的检查默认是不启用的,这是因为这些程序被认为是安全的。如果希望对程序启用SecurityManager类的检查,那么可以通过虚拟机启动参数“-Djava.security.manager”来启用默认的安全管理器实现。如果程序使用了自定义的SecurityManager类的实现,那么可以使用类似“-Djava.security.manager=com.java7book.chapter13.MySecurityManager”的方式来指定自定义安全管理器的类名。使用System类的setSecurityManager方法可以在运行时设置需要使用的安全管理器的实现。在启用了安全管理器之后,会发现很多原先正常执行的代码都会抛出AccessControlException异常,这是因为Java标准库中的权限检查代码开始生效,这时程序要提供自己的策略文件来添加所需的权限。代码清单13-7给出了使用SecurityManager类来进行权限检查的示例,在进行文件写入操作之前先检查是否具有相应的权限。

代码清单13-7 使用SecurityManager类进行权限检查


public void writeFile(Path path, byte[]content)throws IOException{

SecurityManager securityManager=System.getSecurityManager();

if(securityManager!=null){

securityManager.checkWrite(path.toString());

}

Files.write(path, content);

}


权限检查也可以由java.security.AccessController类来完成。AccessController类的checkPermission方法用来检查参数中Permission类的对象所表示的权限在当前的访问控制上下文和策略中是否合法。如果合法,那么checkPermission方法直接返回;否则抛出AccessControlException异常。代码清单13-8给出了使用AccessController类实现与代码清单13-7中相同的权限检查功能的示例。

代码清单13-8 使用AccessController类进行权限检查


public void writeFile(Path path, byte[]content)throws IOException{

FilePermission permission=new FilePermission(path.toString(),"write");

AccessController.checkPermission(permission);

Files.write(path, content);

}


AccessController类是在SecurityManager类之后被引入到Java标准库中的,可以用来替代SecurityManager类的功能。不过在Java标准库早期版本中使用Security-Manager类所做的权限检查,在引入AccessController类之后并没有被替换成使用AccessController类的实现,只是对SecurityManager类的实现进行了修改,改为通过调用AccessController类中的方法完成相关的权限检查。在程序中应该优先使用AccessController类进行权限检查。