• 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.调用程序所调用(直接或间接)的后续对象都有上述权限。

    加油,愿被这世界温柔以待 ^_^
  • 相关阅读:
    异步解决方案----Promise与Await
    多页应用 Webpack4 配置优化与踩坑记录
    左侧固定,右侧自适应的布局方式(新增评论区大佬教的方法)
    精读《Epitath 源码
    如何编写 Typescript 声明文件
    状态码具体解释
    LINQ体验(2)——C# 3.0新语言特性和改进(上篇)
    kafka教程
    double x = 10 ,y = 0;y = x % 2; 这个表达式正确吗?
    mongodb mapreduce使用总结
  • 原文地址:https://www.cnblogs.com/liruilong/p/14810513.html
Copyright © 2020-2023  润新知