AccessController.doPrivileged

 参考博客:

https://blog.csdn.net/jiangtianjiao/article/details/87909065

https://www.iteye.com/blog/huangyunbin-1942509

我的需求:

今天在学设计模式,学到模板方法,看到Arrays.sort()方法里调用有用到这个类,不认识,

我是这样做的:

百度百度研究下:

 

AccessController.doPrivileged在底层源码中会出现,本文对它进行一个简单介绍及如何使用的说明。

首先解释一下几个相关概念保护域

类被装入jvm,为每个类指定一个保护域,保护域定义了授予一段特定代码的所有权限,一个保护域对应一个策略policy.txt文件的一个或者多个grant子句,被装入jvm的每一个类型仅属于一个保护域。

那么一个类型如何被指派到保护域呢?
类装载器知道自己装载的所有类和接口的代码库和签名者,它利用这些信息生成CodeSource对象,将CodeSource对象传递给当前policy对象(policy对象代表了一个从代码来源到权限的全局映射,最终还是由类装载器负责决定代码执行时获取什么样权限)的getPermssions方法,得到PermissionCollection抽象类的子类实例,PermissionCollection包含所有Permission对象的引用,利用它创建的CodeSource和它从Policy对象得到的PermissionCollection,可以实例化一个新的保护域PretectDomain对象,然后传递给defineClass方法,来将这段代码放入保护域内。

顺便描述一下以下三个类加载器使用到方法
loadClass:调用findLoadedClass(String) 这个方法,查看这个Class是否已经被加载,如果没有被加载,继续往下走,查看父类加载器,递归调用loadClass(),如果父类加载器是null,说明是启动类加载器,查找对应的Class,如果都没有找到,就调用findClass,一般被重写。
findClass:根据名称或位置加载.class字节码,然后使用defineClass,通常由子类去实现。
defineClass:解析定义.class字节流,返回class对象。

如下Friend和Friend$1是friend.jar的两个class文件

访问控制器
java.security.AccessController提供了一个默认的安全策略执行机制,它使用栈检查来决定潜在不安全的操作是否被允许。
AccessController最核心方法是它的checkPermission静态方法,该方法决定一个特定的操作是否被允许。允许则简单返回,禁止则抛出AccessControlException异常。checkPermission自顶向下检查栈帧,每个栈帧代表了当前线程调用的某个方法,每一个方法是在某个类中定义,每个类又属于某个保护域,每个保护域包含一些权限,因此每个栈帧间接和一些权限相关,要遇到一个没有权限帧就抛出异常。栈检查可以通过使用doPrivileged方法来中断,后续的栈帧对操作的资源不论是否有权限都无关

implies()方法
表示当前Permission对象 (this) 是否暗含了指定 Permission 对象(permission) 的权限。
permission 子类必须实现此方法,因为它们是惟一能在 permission 对象上施加语义的类。
Java 中给出一个经典实现:BasicPermission,它使用了传入的字符串作为权限的标志,并使用类似于相对路径的办法比较一个 Permission 是否暗含了另一个Permission 的权限。

import java.security.BasicPermission;
import java.security.PermissionCollection;
public class ImpliesTest {
    public ImpliesTest() {
    }
 
    public static void testImplies() {
        MyPermission usaBp = new MyPermission("usa.*"); //全美国
        MyPermission chinaBp = new MyPermission("china.*"); //全中国
        MyPermission hubeiBp = new MyPermission("china.hubei.*"); //全湖北省
        MyPermission wuhanBp = new MyPermission("china.hubei.wuhan.*"); //全武汉市
        MyPermission wuchangBp = new MyPermission("china.hubei.wuhan.wuchang.*"); //全武昌区
 
        System.out.println(chinaBp.implies(usaBp)); //false全美国并不暗含全中国
        System.out.println(hubeiBp.implies(wuchangBp)); //true全湖北暗含了全武昌
        System.out.println(hubeiBp.implies(chinaBp)); //false全湖北并不暗含全中国
 
        // Java 对于权限还给出一个权限集合类PermissionCollection,它是一组权限的并集。
        // 对任意给定的Permission进行测试权限,只要被这个集合中的任意一个Permission 暗含即可。
        // 需要注意的是,该集合中只能是同种类型的Permission。
        PermissionCollection bpc = usaBp.newPermissionCollection();
        bpc.add(chinaBp);
        System.out.println(bpc.implies(hubeiBp)); //true(全美国 | 全中国)暗含了全湖北
    }
 
    public static void main(String[] args) {
        testImplies();
    }
}
class MyPermission extends BasicPermission {
    private static final long serialVersionUID = 1L;
    public MyPermission(String name) {
        super(name);
    }
}
 
// 通过文件目录读权限测试implies方法
Permission file = new FilePermission("/tmp/f", "read"); 
Permission star= new FilePermission("/tmp/*", "read"); 
boolean sif = star.implies(file) // 输出true
boolean fis= file.implies(star)  // 输出false

栈检查机制
假设有这样一种情况:程序A想在/tmp目录中新建一个文件,它没有相应的权限,但是它引用了另外一个B.Jar包,刚好B有权限在/tmp目录中新建文件,而B在新建文件的时候采用的是AccessController.doPrivileged方法进行的,这种情况下A就可以调用B的创建文件方法进行文件创建。

AccessController.doPrivileged中断了栈检查过程,使得后续原本没有权限的代码也可以正常执行,从而成功创建文件,如果不使用AccessController.doPrivileged,会一直进行栈检查直到栈底位置,在程序A的栈帧(栈底)中会抛出权限异常,文件创建失败。

示例参考:http://www.blogjava.net/Phrancol/articles/259069.html

public void doService() {

        // doFileOperation();

        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                doFileOperation();
                return null;
            }
        });
    }

总结:
在某一个线程的调用栈中,当 AccessController的checkPermission方法被最近的调用程序调用时,对于程序要求的所有访问权限,ACC决定是否授权的基本算法如下:
1. 如果调用链中的某个调用程序没有所需的权限,将抛出AccessControlException。
2. 若是满足以下情况即被授予权限:
    a.调用程序访问另一个有该权限域里程序的方法,并且此方法标记为有访问特权。
    b.调用程序所调用(直接或间接)的后续对象都有上述权限。

加油,愿被这世界温柔以待 ^_^
原文地址:https://www.cnblogs.com/liruilong/p/14810513.html