赴美生子 月子中心 美宝论坛

如何使用动态代理实现权限验证

        AOP(即面向方面编程)的一个最重要的职责就是把那些与业务无关的方面剥离出来,开发人员在开发业务模块的时候不用去考虑什么权限管理,日志记录等,其实这些都是很公用的部分,应该有单独的模块去做这样的事情。而动态代理是实现AOP的一个关键技术,其通过动态为目标类生成代理的方式,动态织入相关的代码,扩充被代理类的功能。听起来似乎挺神奇的,马上我将给大家展示动态代理的奇妙之处。(我前面翻译过一篇从CodeProject上获取的关于介绍动态代理的文章,如果对动态代理还不熟悉的可以去看看。)

        好,现在我们就开始吧!

        我先简单描述一下要完成的功能(如图): 
       
 

        有一个窗体,上面有三个按钮,现在我们需要对其进行权限控制,控制哪些按钮可以操作,哪些不可以操作,而且当权限控制发生改变时不会去修改代码,只需要简单修改配置即可。

       首先我们建一个工程,名字随个人喜好啦,(由于本人使用的机器是装的VS2005英文版,所以Demo也是用它完成的,其中可能有些文件的组织方式是按照VS2005来的,不过也没关系,只要把partial类的内容合并了就可以放在2003下面用了)
配置文件内容如下:

 1<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的引用,然后就可以开始写代码了。

设计好窗体(这里就不再详细说明了),然后创建一个拦截器:

 1/******************************
 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的该方法,并且在其中使用了模板方法模式,

 1namespace Castle.DynamicProxy
 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对象,通过其名字判断了是否具有执行方法的权限,有则执行,没有就忽略。
做好了拦截器,可以来产生窗体的代理了

 1/******************************
 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个按钮的事件方法可能是这样的:

 1  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下载

posted @ 2005-12-05 17:53  SuperBowl  阅读(4436)  评论(8编辑  收藏  举报