如何使用动态代理实现权限验证
2009-02-07 10:06 宝宝合凤凰 阅读(425) 评论(0) 收藏 举报如何使用动态代理实现权限验证
好,现在我们就开始吧!
我先简单描述一下要完成的功能(如图):
有一个窗体,上面有三个按钮,现在我们需要对其进行权限控制,控制哪些按钮可以操作,哪些不可以操作,而且当权限控制发生改变时不会去修改代码,只需要简单修改配置即可。
首先我们建一个工程,名字随个人喜好啦,(由于本人使用的机器是装的VS2005英文版,所以Demo也是用它完成的,其中可能有些文件的组织方式是按照VS2005来的,不过也没关系,只要把partial类的内容合并了就可以放在2003下面用了)
配置文件内容如下:
<configuration>2
<configSections>3
<!--用来配置权限的配置节-->4
<section name="PopedomControlList" type="System.Configuration.DictionarySectionHandler"/> 5
</configSections>6

7
<!--控制信息,这里控制了按钮的访问权限-->8
<PopedomControlList>9
<add key="btnOne" value="true"/>10
<add key="btnTwo" value="true"/>11
<add key="btnThree" value="false"/>12
</PopedomControlList>13
14
</configuration>配置文件中配置了我对3个按钮的访问权限,true为可以访问,false不能访问。
OK,我们再在工程中添加对Castle.DynamicProxy.dll的引用,然后就可以开始写代码了。
设计好窗体(这里就不再详细说明了),然后创建一个拦截器:
/******************************2
* 作者:米小波3
* 日期:2005-12-054
* ****************************/5
6

7
using System;8
using System.Collections.Generic;9
using System.Text;10
using System.Windows.Forms;11

12
using Castle.DynamicProxy;13

14
namespace PopedomDemo15
{16
/// <summary>17
/// 实现方法调用拦截处理18
/// </summary>19
public class MyInterceptor : StandardInterceptor20
{21

22
IInterceptor Members47
/// <summary>48
/// 检查按钮权限49
/// </summary>50
/// <param name="btnName"></param>51
/// <returns></returns>52
private bool Check(string btnName)53
{54
if (Program.PopedomList[btnName] != null)55
{56
if (Program.PopedomList[btnName].ToString().ToLower() == "true")57
{58
return true;59
}60
}61
return false;62
}63
}64
}65

上面代码中,我们重载了StandardInterceptor的Intercept方法,这个是拦截器必须实现的IInterceptor中的方法,StandardInterceptor实现了IInterceptor的该方法,并且在其中使用了模板方法模式,
namespace Castle.DynamicProxy2
{3
using System;4

5
[Serializable]6
public class StandardInterceptor : IInterceptor7
{8
public StandardInterceptor() { }9
protected virtual void PreProceed(IInvocation invocation, params object[] args) { }10
protected virtual void PostProceed(IInvocation invocation, ref object returnValue, params object[] args) { }11

12
public virtual object Intercept(IInvocation invocation, params object[] args)13
{14
PreProceed(invocation, args);15
object retValue = invocation.Proceed(args);16
PostProceed(invocation, ref retValue, args);17
return retValue;18
}19
}20
}如果只是简单的拦截处理,重载其
void PostProceed(IInvocation invocation, ref object returnValue, params object[] args)
void PreProceed(IInvocation invocation, params object[] args)
两个方法就可以了,但是我们这里需要直接重载Intercept方法。
在Intercept方法判断了调用方法button对象,通过其名字判断了是否具有执行方法的权限,有则执行,没有就忽略。
做好了拦截器,可以来产生窗体的代理了
/******************************2
* 作者:米小波3
* 日期:2005-12-054
* ****************************/5
using System;6
using System.Collections;7
using System.Windows.Forms;8
using System.Configuration;9

10
using Castle.DynamicProxy;11

12
namespace PopedomDemo13
{14
static class Program15
{16
/// <summary>17
/// 全局权限信息18
/// </summary>19
public static Hashtable PopedomList = new Hashtable();20

21
/// <summary>22
/// The main entry point for the application.23
/// </summary>24
[STAThread]25
static void Main()26
{27
28
PopedomList.Clear();29
30
//从配置文件读取权限信息31
IDictionary dir = (IDictionary)System.Configuration.ConfigurationSettings.GetConfig("PopedomControlList");32
string[] keys = new string[dir.Keys.Count];33
string[] values = new string[dir.Keys.Count];34
dir.Keys.CopyTo(keys, 0);35
dir.Values.CopyTo(values, 0);36
for (int i = 0; i < keys.Length; i++)37
{38
PopedomList.Add(keys[i], values[i]);39
}40
try41
{42
ProxyGenerator gen = new ProxyGenerator();43
frmDemoMain frm = (frmDemoMain)gen.CreateClassProxy(typeof(frmDemoMain), new MyInterceptor());44

45
//Application.EnableVisualStyles();46
//Application.SetCompatibleTextRenderingDefault(false);47
Application.Run(frm);48
}49
catch (Exception ex)50
{51
string msg = ex.Message;52
}53

54

55
}56
}57
}代码中前半部分是读取权限信息,后面则会为该窗体生成一个动态的代理
ProxyGenerator gen = new ProxyGenerator();
frmDemoMain frm = (frmDemoMain)gen.CreateClassProxy(typeof(frmDemoMain), new MyInterceptor());
记住有一点,需要被拦截处理的方法需要是虚方法,可被重载的,其实动态代理的生成原理就是继承了该类,并重载了其虚方法。
所以3个按钮的事件方法可能是这样的:
private void frmDemoMain_Load(object sender, EventArgs e)2
{3
}4

5
public virtual void btnOne_Click(object sender, EventArgs e)6
{7
MessageBox.Show("BtnOne Process-1");8
}9

10
public virtual void btnTwo_Click(object sender, EventArgs e)11
{12
MessageBox.Show("BtnTwo Process-2");13
}14

15
public virtual void btnThree_Click(object sender, EventArgs e)16
{17
MessageBox.Show("BtnTwo Process-3");18
}19

写完了,回头看看代码,对于窗体里面的逻辑几乎不会增加任何与权限有关的代码,很干净。而且动态代理使用的委托技术,并不会对性能造成影响,所以利用它来处理与业务无关的方面是再好不过啦
本示例完整的程序代码可以到https://files.cnblogs.com/mixiaobo/PopedomDemo.rar下载
return base.Intercept(invocation, args);
处出现异常:
未处理的“System.ExecutionEngineException”类型的异常出现在 system.windows.forms.dll 中。
如何解决呢?
{
MessageBox.Show("BtnOne Process-1");
}
那么invocation.Proceed(args) 与其等同,我们的织入就是在这个原始调用的基础上进行各种包装
2、 public override object Intercept(IInvocation invocation, params object[] args)
就是一个拦截方法,里面开发人员可以对原始调用进行各种加工,标准的拦截器是在原始调用的前后织入代码,如:
public virtual object Intercept(IInvocation invocation, params object[] args)
13 {
14 PreProceed(invocation, args);
15 object retValue = invocation.Proceed(args);
16 PostProceed(invocation, ref retValue, args);
17 return retValue;
18 }
本文章的示例是通过拦截,决定原始方法时候被执行,只有权限检查通过的才会被执行 ,如:
if (args.Length > 0)
27 {
28 Button btn = args[0] as Button;
29 if (btn != null)
30 {
31 string btnName = btn.Name;
32 if (Program.PopedomList.Contains(btnName))
33 {
34 if (Check(btnName))
35 {
36 return invocation.Proceed(args);
37 }
38 return null;
39 }
40 }
41 }
42 return base.Intercept(invocation, args);


浙公网安备 33010602011771号