PermissionSet 具有名称的权限集和只读权限集 基于特性的PermissionSetAttribute

来源:互联网 发布:魔晶幻想战魂进阶数据 编辑:程序博客网 时间:2024/05/14 08:49

1. 基础类:PermissionSet

PermissionSet(System.Security命名空间内)代表一个最基本的权限集,使用此类,可以把一些权限(IPermission接口的继承类)包装成一个集合来一并使用,它继承ICollection接口(但只能添加IPermission成员)和IStackWalk接口,这个IStackWalk接口可以使它和代码访问安全权限一样进行调用栈遍历的Demand方法,还有Deny,Assert等方法。

(IStackWalk继承类)

image

 

另一点重要的是PermissionSet没有继承IPermission接口,但是有IPermission接口的类似方法,即Copy,Intersect,Union和IsSubsetOf。或许IPermission只代表单个具体权限,所以PermissionSet没有这样做。

 

PermissionSet的一个构造函数参数是PermissionState枚举,这个构造函数在其他IPermission派生的权限类中也很常见。这个枚举有两个值:None和Unrestricted。分别代表一个空的权限集和全部权限,用这个枚举可以简单得测试一下当前代码的调用堆栈是否全部被赋予全部信任或者是部分信任环境(又称沙盒sandboxing)。

            //using System.Security;

            //using System.Security.Permissions;

            try

            {

                newPermissionSet(PermissionState.Unrestricted).Demand();

                Console.WriteLine("全部信任");

            }

            catch (SecurityException)

            {

                Console.WriteLine("调用堆栈中包含部分信任环境代码");

            }

 

 

 

使用PermissionState.None变可以可以创建一个空的权限集合,并使用AddPermission方法加入自己的权限对象(参数是IPermission对象)。比如下面代码,要求当前代码执行堆栈必须有所有对C盘Windows文件夹的操作权限和注册表操作权限,否则SecurityException异常抛出。

            var perSet= newPermissionSet(PermissionState.None);

            perSet.AddPermission(newFileIOPermission(FileIOPermissionAccess.AllAccess,@"C:\windows"));

            perSet.AddPermission(newRegistryPermission(PermissionState.Unrestricted));

 

            perSet.Demand();

 

PermissionSet还有拷贝,修改等更多操作方法,来看下面的示例代码:

            var perSet= newPermissionSet(PermissionState.None);

            perSet.AddPermission(newUIPermission(PermissionState.Unrestricted));

            perSet.AddPermission(newSecurityPermission(SecurityPermissionFlag.Execution));

 

            //拷贝权限集,也可以使用构造函数:

            //-> var perSet2 = new PermissionSet(perSet);

            var perSet2= perSet.Copy();

            perSet2.RemovePermission(typeof(SecurityPermission));

 

            Console.WriteLine(perSet2.Count);

            //输出:1    因为perSet2删除了SecurityPermission

 

            Console.WriteLine(perSet.Intersect(perSet2).Count);

            //输出:1    因为两个集合共同有UIPermission

 

            Console.WriteLine(perSet2.Union(perSet).Count);

            //输出:2    两个集合交集等于parSet的大小

 

            Console.WriteLine(perSet2.IsSubsetOf(perSet));

            //输出:True perSet2等于没有SecurityPermission的parSet

 

 

 

最后PermissionSet是可以序列化的,也可以用ToXml和FromXml去保存一个权限集。关于XML的方法会操作一个叫SecurityElement的类,这个只需要调用它的ToString方法便可以得道XML文本:

            var perSet= newPermissionSet(PermissionState.None);

            perSet.AddPermission(newUIPermission(PermissionState.Unrestricted));

            Console.WriteLine(perSet.ToXml().ToString());

 

输出权限集的XML形式:

 

<PermissionSetclass="System.Security.PermissionSet"version="1">

    <IPermissionclass="System.Security.Permissions.UIPermission, mscorlib, Version=

                        4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

    version="1"

    Unrestricted="true"/>

</PermissionSet>

 

这两种权限集分别对应PermissionSet类的两个派生类:NamedPermissionSet和ReadOnlyPermissionSet。

NamedPermissionSet就是一个有名称和描述的权限集,分别对应NamedPermissionSet的Name和Description属性,仅此而已。

ReadOnlyPermissionSet也挺简单的,首先修改ICollection的IsReadOnly属性为true,代表一个只读集合。接着改写PermissionSet的一些修改集合的内部方法,这样尝试对ReadOnlyPermissionSet进行修改会抛出异常,最后ReadOnlyPermissionSet只能通过SecurityElement来构建。

            var perSet= newPermissionSet(PermissionState.None);

            perSet.AddPermission(newUIPermission(PermissionState.Unrestricted));

 

            //创建具有名称的权限集

            var namedSet= newNamedPermissionSet("MyName", perSet);

            //创建只读权限集

            var readonlySet= newReadOnlyPermissionSet(perSet.ToXml());

 

            //输出NamedPermissionSet的名称

            Console.WriteLine(namedSet.Name);

 

            //输出 "修改失败"

            try

            {

                readonlySet.AddPermission(newSecurityPermission(PermissionState.Unrestricted));

            }

            catch

            {

                Console.WriteLine("修改失败");

            }

 

3. 基于特性的PermissionSetAttribute

.NET大多数权限都有特性类型的支持。也是所谓的Declarative和Imperative样式(声明和命令)。比如下面两种Demand方法是等价的:

        //命令样式(Imperative)

        staticvoid test1()

        {

            newFileIOPermission(PermissionState.Unrestricted).Demand();

        }

 

        //声明样式(Declarative)

        [FileIOPermission(SecurityAction.Demand, Unrestricted= true)]

        staticvoid test2()

        { }

注意SecurityAction枚举不仅仅有IStackWalk支持的Demand,Deny,Assert和PermitOnly。还有额外的LinkDemand,InheritanceDemand,RequestMinimum……等值,这些值的安全验证不发生在调用堆栈遍历,可能发生在程序集加载时间,JIT编译等。

 

使用PermissionSetAttribute特性(在System.Security.Permissions命名空间内)也可以使一个PermissionSet进行声明样式的权限操作。

你可以使用File,XML,Hex等众多属性来制定权限集的位置:

        [PermissionSet(SecurityAction.Demand, File= @"C:\a.xml")]

        staticvoid test()

        { }

 

 

注意:

上面代码在我的Visual C# 2010 Express SP1上编译总出现如下错误:

Error emitting 'System.Security.Permissions.PermissionSetAttribute' attribute -- 'Unable to create an instance of the permission for this attribute.'

去掉File属性的定义就没事了,不知道为什么,谷歌查询结果竟然只有一个匹配而且也是未解决的问题,拷贝了MSDN的相关类的源代码,仍然有错误。不解……

 

不过,PermissionSetAttribute的最大作用是通过设置它的Name属性便可以引用一个预定义的.NET权限集,如下:(可以参考:http://msdn.microsoft.com/zh-cn/library/4652tyx7.aspx)

  • Nothing

无权限(代码无法运行)。

  • Execution

拥有运行(执行)权限,但是没有使用受保护资源的权限。

  • Internet

适用于来源不明的内容的默认策略权限集。

  • LocalIntranet

企业内的默认策略权限集。

  • Everything

所有标准(内置)权限(跳过验证的权限除外)。

  • FullTrust

对所有资源的完全访问权。

 

 

这样的话,下面的代码也是等价的:

        //using System.Security;

        //using System.Security.Permissions;

 

        [PermissionSet(SecurityAction.Demand, Name= "FullTrust")]

        staticvoid test1()

        { }

 

        staticvoid test2()

        {

            newPermissionSet(PermissionState.Unrestricted).Demand();

        }

 

 

更新:

如果想获取一个预定义的PermissionSet对象,可以参考这一篇文章:通过Zone Evidence获取.NET(C#)中的预定义权限集

 

 

结合SecurityAction.RequestMinimum(必须应用在程序集上),可以强制程序集在被加载的时候确保被给予全部信任:

[assembly:PermissionSet(SecurityAction.RequestMinimum, Name= "FullTrust")]

(不过在.NET 4.0后,上面的方法被标记为废弃,因为.NET 4.0引入了新的安全模型)

 

 

 

作者:Mgen
出处:www.cnblogs.com/mgen

本文版权归作者所有,欢迎以网址(链接)的方式转载,不欢迎复制文章内容的方式转载,其一是为了在搜索引擎中去掉重复文章内容,其二复制后的文章往往没有提供本博客的页面格式和链接,造成文章可读性很差。望有素质人自觉遵守上述建议。

如果一定要以复制文章内容的方式转载,必须在文章开头标明作者信息和原文章链接地址。否则保留追究法律责任的权利。