如何使用动态代理实现权限验证
好,现在我们就开始吧!
我先简单描述一下要完成的功能(如图):
有一个窗体,上面有三个按钮,现在我们需要对其进行权限控制,控制哪些按钮可以操作,哪些不可以操作,而且当权限控制发生改变时不会去修改代码,只需要简单修改配置即可。
首先我们建一个工程,名字随个人喜好啦,(由于本人使用的机器是装的VS2005英文版,所以Demo也是用它完成的,其中可能有些文件的组织方式是按照VS2005来的,不过也没关系,只要把partial类的内容合并了就可以放在2003下面用了)
配置文件内容如下:
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-05
4 * ****************************/
5
6
7using System;
8using System.Collections.Generic;
9using System.Text;
10using System.Windows.Forms;
11
12using Castle.DynamicProxy;
13
14namespace PopedomDemo
15{
16 /// <summary>
17 /// 实现方法调用拦截处理
18 /// </summary>
19 public class MyInterceptor : StandardInterceptor
20 {
21
22 IInterceptor Members
47 /// <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的该方法,并且在其中使用了模板方法模式,
2{
3 using System;
4
5 [Serializable]
6 public class StandardInterceptor : IInterceptor
7 {
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-05
4 * ****************************/
5using System;
6using System.Collections;
7using System.Windows.Forms;
8using System.Configuration;
9
10using Castle.DynamicProxy;
11
12namespace PopedomDemo
13{
14 static class Program
15 {
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 try
41 {
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个按钮的事件方法可能是这样的:
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下载