前面好几篇文章,老周都跟大伙伴们聊了跟应用程序域有关的话题,干脆咱们一聊到底吧,做学问就应该这样,有恒心。

App Domain的创建新应用程序域的方法中,有一个特殊的重载:

public static AppDomain CreateDomain(string friendlyName, Evidence securityInfo, AppDomainSetup info, PermissionSet grantSet, params StrongName[] fullTrustAssemblies);

这个重载比较特殊,它与咱们今天扯的话题接近,因为它的参数列表中有一个是 PermissionSet 类型的,它表示一个权限的集合,当创建应用程序域时,通过这个权限集合,限制在新应用程序域中执行的代码的权限。在各个CreateDomain方法的重载中,只有这个有设置权限集的参数。

运用这个重载方法,可以将你觉得要限制权限的代码放到这个新的应用程序域中执行,即创建一个“沙箱”。比如,你拿到别人写的一个类库A,不过你不知道这个类库A在执行过程中会干什么,于是,你希望在使用这个来路不明的类库时,可以限制一下它,例如不让它读写文件,或者说只允许它访问某些目录和文件。

为了偷工减料,写出豆腐渣程序,老周举的这个例子,是把做测试用的代码写到主程序集中。它有一个类,类中有一个方法,调用之后,会在“文档”库中创建一个文件,然后写入一些见不得人的内容。

    public class Demo : MarshalByRefObject
{
public void WirteFile()
{
string myDoc = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string filePath = Path.Combine(myDoc, Guid.NewGuid() + ".txt");
using (FileStream fs = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
{
byte[] data = Encoding.UTF8.GetBytes("卖假药啦。");
fs.Write(data, , data.Length);
}
}
}

然后,创建一个新的应用程序域,再在新域里面执行刚刚写好的类。之所以继承MarshalByRefObject类,是希望可以跨应用程序域调用,并且是按引用传递。

调用如下:

            // 添加程序集凭据
// 此处是为了装逼,才写以下几行
// 其实你可以直接用 AppDomain.CurrentDomain.Evidence
Evidence evd = new Evidence();
Assembly currAss = Assembly.GetExecutingAssembly();
Hash hsevd = new Hash(currAss);
evd.AddAssemblyEvidence<Hash>(hsevd); // 准备相关信息
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; // 准备权限
PermissionSet ps = new PermissionSet(PermissionState.None);
// Execution 权限必须,不然连代码都不能执行了
SecurityPermission secps = new SecurityPermission(SecurityPermissionFlag.Execution);
ps.AddPermission(secps); // 创建新域
AppDomain newAppdm = AppDomain.CreateDomain("good", evd, setup, ps);
// 创建测试对象实例
Demo d = (Demo)newAppdm.CreateInstanceAndUnwrap(currAss.FullName, $"{nameof(TestApp)}.{nameof(Demo)}");
d.WriteFile(); d = null;
AppDomain.Unload(newAppdm);

Evidence这东西比较抽象,你可以理解为程序集用来证明它是合法身份的一些信息,比如这里,我用当前程序集的 Hash 值来做为证明,因为这个 Demo 类是写在当前程序集中的(刚刚说了,为了偷工减料)。

注意权限集合是 PermissionSet 类,它是个容器,你可以根据需要,向里面添加权限声明。在上面代码中,我加了一个最基本的安全权限——SecurityPermission,这个你得加,因为它是最最最基本的权限,如果不加,连代码都执行不了,那就等于这段代码是废的,用 SecurityPermissionFlag 枚举来描述代码应具有的基础权限,这些值可以组合使用,Execution表示允许执行代码,如果你连这个权限也不给,干脆把 Demo 类开除算了。

顺便说一下,在new出PermissionSet 实例时,构造函数会要求一个 PermissionState值,你应该把它设置为 None,这样权限才会对代码进行限制,如果用了Unrestricted ,表示不做限制。

调用 CreateInstanceAndUnwrap 方法时,是在新的应用程序域中创建 Demo 实例,但可以通过引用,把实例封送到当前应用程序域中,这样可以跨域调用,实际上 WriteFile 方法是在新的应用程序域中执行的。

如果你要允许代码访问文件和目录,你必须加上FileIOPermission权限,但这里我没加,看看运行后会如何。

因为我不给它权限,所以它没办法写入文件了。

现在我们来改一下代码,在创建应用程序域前,向权限集合添加 FileIOPermission 权限。

            string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
FileIOPermission fps = new FileIOPermission(FileIOPermissionAccess.AllAccess, docPath);
ps.AddPermission(fps);

再执行一下,如果执行成功,会发现“文档”库里面多了一个文件。

好了,今天就扯到这里了。

示例代码下载地址

最新文章

  1. ThinkInside
  2. jquery的事件命名空间详解
  3. python学习笔记-(十六)python操作mysql
  4. JSONObject.fromObject(map)(JSON与JAVA数据的转换)
  5. Ajax跨域的几种方法以及每种方法的原理
  6. angularjs compile和link
  7. VS链接过程中与MSVCRT.lib冲突
  8. 公用表表达式(CTE)引发的改变执行顺序同WHERE条件顺序引发的bug
  9. tachyon 集群安装
  10. ArcGIS Desktop开发基础(转)
  11. hbase on spark
  12. C#设计模式学习资料--观察者模式
  13. Linux服务器上安装vsftpd
  14. Activiti 中的ACT_RU_TASK表中的EXECUTION_ID和PROC_INST_ID区别
  15. 【C#】C#学习笔记_1
  16. 简单聊聊SOA和微服务
  17. Mongodb 安装 和 启动
  18. nc,远程传输文件
  19. ubuntu 使用蓝牙和minicom
  20. Delphi7编译时,发生Access violation at address 00A7B628 in module &#39;dcc70.dll&#39;. Read of address 00000000.(Delphi6升级到Delphi7)

热门文章

  1. mysql每秒最多能插入多少条数据 ? 死磕性能压测
  2. Restful资源文章
  3. ASP.NET是如何在IIS下工作的
  4. Partition2:对表分区
  5. git亲测命令
  6. 再部署一个 instance 和 Local Network - 每天5分钟玩转 OpenStack(131)
  7. [C#] 回眸 C# 的前世今生 - 见证 C# 6.0 的新语法特性
  8. JVM类加载
  9. 怎样在Dos里切换盘符
  10. SQL Server2014 SP2关键特性