可以把Permission理解为java安全的最小单元,是权限的抽象代表。通常一个Permission子类构造器会有两个参数,一个是目标的名称(对谁进行权限控制);另外一个是对目标允许的操作(例如对一个文件读操作)。
Permission是一个抽象类,包含的方法如下:
abstract boolean equals(Object obj);
abstract String getActions();
abstract boolean implies(Permission permission);
PermissionCollection newPermissionCollection();
以其子类FilePermission(表示对文件权限)为例子,来说明具体的用法:
构造函数如下:
FilePermission(String path, String actions);
第一个参数即为权限控制的具体目标(path是文件或者目录的路径名);第二个参数即为对文件的操作,多个操作用逗号分隔,允许的操作包括:
READ、WRITE、EXECUTE、DELETE
对D盘demo.txt文件允许的操作为读和删除,具体写法可为:
FilePermission fp = new FilePermission("D:/demo.txt","read,delete");
我们现在明白了,Permission用来描述一个具体的权限,那么接下来就有问题了,谁将拥有这个权限?
具体来说,我们定义好了一个权限,如:“对D盘demo.txt文件允许的操作为读和删除” 那么我们如何将这个权限授予一段代码?
首先来了解几个概念
1.保护域(protection domain)
意如其名,一块区域。即使是一块区域,那么一定有一些东西属于这个区域,一定有一些东西属性那个区域。
那么放在代码的世界中,也是说有一些代码(类)属于这块保护区,一些代码(类)属于另外一块保护区。
java可以对不同的保护区授予不同的权限,那么这块区域中的代码(类)就会拥有所在保护区的权限。
API的具体体现为:java.security.ProtectionDomain
2.代码源(CodeSource)
一定要能惟一地标识一段代码(类)以保证它的访问权限没有冲突。惟一标识属性共有两项:代码的来源(代码装载到内存所用的 URL)和代码的 signer 实体(由对应于运行代码的数字签名的一组公共密钥指定)
我们知道标识一个类在Java中的唯一性是根据:加载它的类加载器和该类本身
在java中,以类为单位,将不同的类分在不同的保护域。每个类加载器具有一个保护域,使用同一个类加载器加载的类在同一个保护域,也就是说具有相同的权限。
阅读java.security.ProtectionDomain源码,也能发现这个特征。ProtectionDomain类具有classloader属性:
/* ClassLoader the protection domain was consed from */
private ClassLoader classloader ;
同样ProtectionDomain类也包括该区域被授予的权限:
/* the rights this protection domain is granted */
private PermissionCollection permissions ;
下面跟着我来阅读类加载器(java.lang.ClassLoader)的部分源码:
默认保护域:
// The "default" domain. Set as the default ProtectionDomain on newly
// created classes.
private final ProtectionDomain defaultDomain =
new ProtectionDomain(new CodeSource( null, (Certificate[]) null ),null , this , null);
new ProtectionDomain的第二个参数代表授予的权限集合,默认值为null。
类加载方法:
protected final Class > defineClass(String name , byte[] b , int off , int len,
ProtectionDomain protectionDomain )
throws ClassFormatError
{
protectionDomain = preDefineClass(name , protectionDomain );
Class c = null;
String source = defineClassSourceLocation(protectionDomain );
try {
//本地方法加载类
c = defineClass1( name, b, off, len, protectionDomain , source );
} catch (ClassFormatError cfe ) {
c = defineTransformedClass( name, b, off, len, protectionDomain , cfe ,
source);
}
postDefineClass( c, protectionDomain );
return c ;
}
private ProtectionDomain preDefineClass(String name,ProtectionDomain pd )
{
if (!checkName(name ))
throw new NoClassDefFoundError( "IllegalName: " + name);
if ((name != null) && name.startsWith( "java." )) {
throw new SecurityException
( "Prohibited package name: " +
name.substring(0, name .lastIndexOf('.' )));
}
if (pd == null) {
pd = defaultDomain ;
}
if (name != null) checkCerts( name, pd .getCodeSource());
return pd ;
}
该方法的第五个参数为保护域,也就是说在手动加载类时可以自定义保护域。如果该参数为null,则使用默认保护域。
现在已经规定了不同类拥有不同的权限,那么由谁来监督类有没有越权呢?