博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用EntLib授权机制实现对ASP.NET页面的自动授权
阅读量:5887 次
发布时间:2019-06-19

本文共 6087 字,大约阅读时间需要 20 分钟。

ASP.NET默认采用和分别实现针对请求地址和物理文件的授权,但是在很多情况下我们需要额外的授权方式。Entlib提供了一种基于表达式的授权方式,它允许我们以一个表达式的方式来定义授权的规则。在新的项目中我们希望利用EntLib的授权框架来实现针对ASP.NET页面的自动授权,本文描述的解决方案是我刚刚想到的,希望广大网友朋友们帮助评估一下。[源代码从下载]

目录

一、实例演示
二、AuthorizationFilterAttribute
三、AuthorizeAttribute
四、PageBase

一、实例演示

我们先来作一个简单的实例演示。如下所示的EntLib安全模块的配置,如果读者对此不了解也没有关系,在这里我们只需要关注定义其中的一个授权规则(Authorization Rule):“I:Foo OR R:Admin”。这是一个逻辑表达式,前缀I:和R:分别表示用户名(Identity)和角色(Role),整个表达式表示的授权逻辑是:“帐号为Foo的用户和所有具有Admin角色的用户”有权限方法与此表达式关联的操作或者资源。配置还定义了该授权规则的名称“FooOrAdmin”。

1: 
2:   
3:     
4:              type="Microsoft.Practices.EnterpriseLibrary.Security.Configuration.SecuritySettings,
5:                    Microsoft.Practices.EnterpriseLibrary.Security"/>
6:   
7:   
8:     
9:       
10:            type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider,
11:                  Microsoft.Practices.EnterpriseLibrary.Security">
12:         
13:           
14:         
15:       
16:     
17:   
18: 

我们添加一个需要授权的Web页面(Default.aspx),并且使用上面定义的表达式来作为该页面的授权规则,我们通过自定义的AuthorizeAttribute特性实现两者之间的关联(该特性构造函数中指定的字符串正是配置的授权规则名称)。除此之外,Web页面对应的类型继承自我们自定义的基类PageBase。

1:
2: public partial class Default :
3: {
4: }

我们随后添加一个登录页面,具体的实现就不再这里一一介绍了。为了模拟不同的登录用户具有不同的权限,我们通过注册HttpApplication的AuthenticateRequest事件来对当前Principal进行定制。具体的定义如下所示:如果用户名为Bar,我们让当前的Principal具有Admin角色,对于其他帐号的登录用户,角色列表为空。

1: public class Global : System.Web.HttpApplication
2: {
3:     protected void Application_AuthenticateRequest(object sender, EventArgs e)
4:     {
5:         if (null == HttpContext.Current.User || !HttpContext.Current.User.Identity.IsAuthenticated)
6:         {
7:             return;
8:         }
9: 
10:         IIdentity identity = new GenericIdentity(HttpContext.Current.User.Identity.Name);
11:         string[] roles = null;
12:         if (identity.Name.ToLower() == "bar")
13:         {
14:             roles = new string[] { "" };
15:         }
16:         HttpContext.Current.User = new GenericPrincipal(identity, roles);
17:     }
18: }

由于页面Default.aspx与配置名称为FooOrAdmin的授权规则进行了关联,根绝授权规则表达式定义和针对不同用户的角色列表,意味着当我们以账户Foo和Bar登录后才能访问该页面,“自动化授权”可以通过下图得到证实:当前用户为Foo和Bar时,页面得以正常显示;而当我们以Baz的身份登录后,显示“Access denied…”。

二、AuthorizationFilterAttribute

这里我吸取了ASP.NET MVC基于AuthorizationFilter的授权方式,不同的是AuthorizationFilter在ASP.NET MVC中以特性的方式应用到Controller类型和Action方法上,这里我们则将它应用到Web页面对应的类上。AuthorizationFilterAttribute作为授权筛选器特性的基类定义如下,由于多个特性可以同时应用到同一个类型上,它们的执行顺序通过属性Order来控制。具体的授权判断以及对非授权请求的处理定义在方法OnAuthorization方法上。

1: [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)]
2: public abstract class AuthorizationFilterAttribute:Attribute
3: {
4:     public int Order { get; set; }
5:     public abstract bool OnAuthorization(AuthorizationContext context);
6: }
7: 
8: public class AuthorizationContext
9: {
10:     public HttpContext  HttpContext { get; private set; }
11:     public bool         UnAuthorizedRequestHandled { get; set; }
12: 
13:     public AuthorizationContext(HttpContext httpContext)
14:     {
15:         this.HttpContext = httpContext;
16:     }
17: }

OnAuthorization方法返回值代表的是真否授权的判断,它具有一个类型为AuthorizationContext参数。AuthorizationContext是对HttpContext对象的封装,属性UnAuthorizedRequestHandled 表示是否完成了针对非授权请求的处理。如果多个AuthorizationFilterAttribute应用到同一个类型上,如果前面执行的AuthorizationFilterAttribute将传入的AuthorizationContext的这个属性设置为True,后续的将不在执行。

三、AuthorizeAttribute

基于EntLib的授权通过AuthorizeAttribute来实现。如下面的代码片断所示,AuthorizeAttribute 直接继承自AuthorizationFilterAttribute,代表授权规则配置名称的属性AuthorizationRule 在构造函数中被初始化。在实现的OnAuthorization我们按照Entlib授权框架的编程模式判断当前Principal是否具有针对指定授权规则的权限,对于非授权请求我们直接调用HandleUnauthorizedRequest方法进行处理。具体的处理逻辑很简单:直接相应一段文字“Access denied…”(正是上面截图中显示的文字)。出于可扩展的考虑,我们将此方法定义成受保护的虚方法。

1: [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)]
2: public class AuthorizeAttribute : AuthorizationFilterAttribute
3: {
4:     public string AuthorizationRule { get; private set; }
5:     public AuthorizeAttribute(string authorizationRule)
6:     {
7:         Guard.ArgumentNotNullOrEmpty(authorizationRule, "authorizationRule");
8:         this.AuthorizationRule = authorizationRule;
9:     }
10: 
11:     public override bool OnAuthorization(AuthorizationContext context)
12:     {
13:         IAuthorizationProvider authorizationProvider = AuthorizationFactory.GetAuthorizationProvider();
14:         if (authorizationProvider.Authorize(context.HttpContext.User, this.AuthorizationRule))
15:         {
16:             return true;
17:         }
18:         this.HandleUnauthorizedRequest(context);
19:         return false;
20:     }
21: 
22:     protected virtual void HandleUnauthorizedRequest(AuthorizationContext context)
23:     {
24:         context.HttpContext.Response.Write(context.HttpContext.User.Identity.Name + ": Access denied...");
25:     }
26: }

四、PageBase

我们知道针对一个ASP.NET 资源的请求最后大都通过一个对应的HttpHandler来处理,这个授权解决方案的基本思路就是通过自定义HttpHandler实现自动化授权检验。Page类型是我们最为熟悉的HttpHandler,为此我们定义了如下一个继承自它的类型PageBase。如下面的代码片断所示,在重写的ProcessRequest方法中实现了对应用在当前类型上的AuthorizationFilterAttribute特性的解析和执行,进而提供了对授权的实现。

1: public abstract class PageBase: Page
2: {
3:     public override void ProcessRequest(HttpContext context)
4:     {
5:         var filterAttributes = this.GetType().GetCustomAttributes(true)
6:                                 .OfType
()
7:                                 .OrderBy(attribute => attribute.Order);
8:         AuthorizationContext authorizationContext = new AuthorizationContext(context);
9:         bool isAuthorized = true;
10:         foreach (AuthorizationFilterAttribute attribute in filterAttributes)
11:         {
12:             isAuthorized = attribute.OnAuthorization(authorizationContext);
13:             if (authorizationContext.UnAuthorizedRequestHandled)
14:             {
15:                 break;
16:             }
17:         }
18: 
19:         if (isAuthorized)
20:         {
21:             base.ProcessRequest(context);
22:         }
23:     }
24: }
作者:蒋金楠
微信公众账号:大内老A
微博:
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号
蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
你可能感兴趣的文章
[转]轻松实现可伸缩性,容错性,和负载平衡的大规模多人在线系统
查看>>
五 数组
查看>>
也谈跨域数据交互解决方案
查看>>
EntityFramework中使用Include可能带来的问题
查看>>
面试题28:字符串的排列
查看>>
css important
查看>>
WPF 实现窗体拖动
查看>>
NULL不是数值
查看>>
Oracle学习笔记之五,Oracle 11g的PL/SQL入门
查看>>
css绘制几何图形
查看>>
结合kmp算法的匹配动画浅析其基本思想
查看>>
Android网络编程11之源码解析Retrofit
查看>>
安全预警:全球13.5亿的ARRIS有线调制解调器可被远程攻击
查看>>
麦子学院与阿里云战略合作 在线教育领军者技术实力被认可
查看>>
正确看待大数据
查看>>
Facebook通过10亿单词构建有效的神经网络语言模型
查看>>
发展大数据不能抛弃“小数据”
查看>>
中了WannaCry病毒的电脑几乎都是Win 7
查看>>
学生机房虚拟化(九)系统操作设计思路
查看>>
nginx报错pread() returned only 0 bytes instead of 4091的分析
查看>>