以下摘自JDK
http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/security/AccessController.html
AccessController 类用于与访问控制相关的操作和决定。
更确切地说,AccessController 类用于以下三个目的:
- 基于当前生效的安全策略决定是允许还是拒绝对关键系统资源的访问,
- 将代码标记为享有“特权”,从而影响后续访问决定,以及
- 获取当前调用上下文的“快照”,这样即可相对于已保存的上下文作出其他上下文的访问控制决定。
checkPermission
方法确定应该批准还是拒绝由指定权限所指示的访问请求。示例调用如下所示。在此例中,checkPermission
将确定是否批准对 "/temp" 目录中名为 "testFile" 的文件的“读”访问。
FilePermission perm = new FilePermission("/temp/testFile", "read");
AccessController.checkPermission(perm);
如果允许请求的访问,则 checkPermission
正常返回。如果拒绝,则抛出 AccessControlException。如果请求的权限类型不正确或包含无效值,则也会抛出 AccessControlException。只要可能,就给出此类信息。 假定当前线程按照调用方 1 到调用方 2 直到调用方 m 的顺序遍历了 m 个调用方。那么调用方 m 调用 checkPermission
方法。checkPermission
方法基于以下算法确定批准还是拒绝访问:
i = m;
while (i > 0) {
if (caller i's domain does not have the permission)
throw AccessControlException
else if (caller i is marked as privileged) {
if (a context was specified in the call to doPrivileged)
context.checkPermission(permission)
return;
}
i = i - 1;
};
// Next, check the context inherited when
// the thread was created. Whenever a new thread is created, the
// AccessControlContext at that time is
// stored and associated with the new thread, as the "inherited"
// context.
inheritedContext.checkPermission(permission);
可以将调用方标记为享有“特权”(请参阅 doPrivileged
及下文)。在做访问控制决定时,如果遇到通过调用不带上下文参数(请参见下文以获取关于上下文参数的信息)的 doPrivileged
标记为“特权”的调用方,则 checkPermission
方法将停止检查。 如果该调用方的域具有指定的权限,则不进行进一步检查并且 checkPermission
正常返回,指示允许所请求的访问。如果该域不具有指定的权限,则通常抛出异常。
“特权”功能的标准用法如下所示。如果不需要从“特权”块返回值,则使用以下代码:
somemethod() {
...normal code here...
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
System.loadLibrary("awt");
return null; // nothing to return
}
});
...normal code here...
}
PrivilegedAction 是一个具有单个方法的接口,该方法名为 run
并返回一个 Object。上述示例显示该接口的实现的创建;提供了 run
方法的具体实现。调用 doPrivileged
时,将 PrivilegedAction 实现的实例传递给它。doPrivileged
方法在启用特权后从 PrivilegedAction 实现调用 run
方法,并返回 run
方法的返回值作为 doPrivileged
返回值(在此示例中忽略)。
如果需要返回值,则可使用以下代码:
somemethod() {
...normal code here...
String user = (String) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return System.getProperty("user.name");
}
}
);
...normal code here...
}
如果在 run
方法中执行的操作可以抛出“已检查”异常(列在方法的 throws
子句中),则需要使用 PrivilegedExceptionAction
接口代替 PrivilegedAction
接口:
somemethod() throws FileNotFoundException {
...normal code here...
try {
FileInputStream fis = (FileInputStream) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws FileNotFoundException {
return new FileInputStream("someFile");
}
}
);
} catch (PrivilegedActionException e) {
// e.getException() should be an instance of FileNotFoundException,
// as only "checked" exceptions will be "wrapped" in a
//PrivilegedActionException
.
throw (FileNotFoundException) e.getException();
}
...normal code here...
}
在使用“特权”构造时务必 * 特别 * 小心,始终让享有特权的代码段尽可能小。
注意,checkPermission
始终在当前执行线程的上下文中执行安全性检查。有时,本来应该在给定上下文中进行的安全性检查实际需要在另一个 上下文中(例如,在 worker 线程中)完成。getContext
方法和 AccessControlContext 类是针对这种情况提供的。getContext
方法获取当前调用上下文的“快照”,并将其置于它所返回的 AccessControlContext 对象中。示例调用如下:
AccessControlContext acc = AccessController.getContext()
AccessControlContext 本身具有一个 checkPermission
方法,该方法基于它 所封装的上下文而不是当前执行线程作出访问决定。因此,另一上下文中的代码可以在以前保存的 AccessControlContext 对象上调用该方法。示例调用如下:
acc.checkPermission(permission)
有时候您还可能不知道用于检查上下文的权限的优先级。这时可以使用 doPrivileged 方法来获取上下文:
somemethod() {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// Code goes here. Any permission checks within this
// run method will require that the intersection of the
// callers protection domain and the snapshot's
// context have the desired permission.
}
}, acc);
...normal code here...
}