您的位置:首页 > 移动开发

如何通过AppDomain用特定的安全上下文加载外部程序集

2008-09-08 15:14 603 查看
.NET的程序集实际上不是直接在进程(Process)中运行,而是在一个特殊的上下文环境(AppDomain)中。我们的程序在运行的时候,首先会由CLR动态创建一个或多个默认的AppDomain,然后我们在代码中还可以手工地创建自定义的AppDomain。

有关程序域的说明,有兴趣的朋友可以参考下面的链接

http://msdn.microsoft.com/zh-cn/library/system.appdomain(VS.80).aspx

实际上它的三大好处是

1. 安全性(不同程序域之间默认是无法通讯的)

2. 稳定性(单一程序域的异常不会影响其他的)

3. 便捷性(可以利用程序域的单独卸载,而不是整个程序卸载)

那么什么时候需要用到这个技术呢?最典型的一个场景就是我们需要设计一个插件结构的程序。我们的主程序可以动态加载一个或者多个插件,这些插件当然可能是别人写的,那么我们对于这些插件所可能会做的事情是不可预期的。为了避免这些插件通过我们的主程序的执行而造成用户受到危害——例如插件可能会去更改注册表等等重要的信息——我们就可以把这些插件单独运行,而且让他们运行在相对比较低的安全上下文中。

下面用一个例子说明,我们大致的原理是用一个单独的应用程序域运行所有的插件,在该应用程序域上设置的权限是Internet这个级别。





核心代码如下

private AppDomain CreateAppDomain()
{
AppDomain result = AppDomain.CreateDomain("plugins");
PolicyLevel policy = PolicyLevel.CreateAppDomainLevel();
PermissionSet ps = policy.GetNamedPermissionSet("Internet");
//这里我们取得Internet这个权限集的默认权限集合
ps.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess, Application.StartupPath));
//并且再为其增加文件读取的权限,因为它需要加载另外的程序集,所以需要有主程序根目录下面的权限
policy.RootCodeGroup.PolicyStatement = new PolicyStatement(ps);
result.SetAppDomainPolicy(policy);
return result;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

下面的代码是菜单响应事件

void item_Click(object sender, EventArgs e)
{
ToolStripMenuItem item = (ToolStripMenuItem)sender;
string tag = item.Tag.ToString();

string fileName = tag.Split(';')[0];
string typeName = tag.Split(';')[1];

BindingFlags bindings = BindingFlags.CreateInstance |
BindingFlags.Instance | BindingFlags.Public;

AssemblyLoader loader = (AssemblyLoader)
pluginDomain.CreateInstanceFromAndUnwrap("Host.exe",
typeof(AssemblyLoader).FullName, true, bindings,
null, new object[] { fileName }, null, null, null);
loader.RunPlugin(typeName);
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

上面的代码中的AssemblyLoader类相当于是一个桥梁,它帮助我们实例化插件并运行里面的入口方法

using System;
using System.Reflection;
using PluginSample.Core;

namespace Host
{
[Serializable]
public class AssemblyLoader:MarshalByRefObject
{
public AssemblyLoader() { }

public AssemblyLoader(string dllName)
{
if (_assembly == null)
_assembly = LoadAssembly(dllName);
}

private Assembly _assembly=null;
public Assembly LoadAssembly(string fileName) {
return Assembly.LoadFile(fileName);
}

public void RunPlugin(string type) {
IPlugin plugin = (IPlugin)_assembly.CreateInstance(type);
plugin.Main();
}

}
}
下面我们来看看运行的效果。首先说说主程序:因为主程序是在本机运行,所以默认使用到的权限集是FullTrust,如下图


我们这个程序会自动地加载plugins目录下面的dll,然后创建菜单。(你这里可以看见两个菜单项,分别对应两个插件)
我们接下去点击插件的菜单,这时候会调用上面贴出来的第二段代码,动态实例化插件,并将其放在单独的程序域中执行
因为我们给程序域设置的权限集是Internet,所以你会看到下面的效果


注意,我们这里为了测试,故意在这个插件上用一个按钮去修改注册表,我们来看看会出现什么情况


很好,这样我们就实现了目的:可以让插件运行,但不允许他去修改注册表。

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: