如何使用动态代理实现权限验证
好,现在我们就开始吧!
我先简单描述一下要完成的功能(如图):
有一个窗体,上面有三个按钮,现在我们需要对其进行权限控制,控制哪些按钮可以操作,哪些不可以操作,而且当权限控制发生改变时不会去修改代码,只需要简单修改配置即可。
首先我们建一个工程,名字随个人喜好啦,(由于本人使用的机器是装的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下载




浙公网安备 33010602011771号