WebForm
在做WebForm的时候,如果我们要实现某页面登陆后才能访问,这个非常容易实现
???public partial class IndexForm : Page ???{ ???????protected void Page_Load(object sender, EventArgs e) ???????{ ???????????//检查是否登录(session/cookie),失败跳转登录,成功继续访问 ???????} ???}
但是实际工作中,不会只有一个页面需要权限检查,当我们面对多个页面的时候,该如何处理呢?这个时候一般会采取下列这种处理方式:
1 ????public partial class IndexForm : BasePage 2 ????{ 3 ????????protected void Page_Load(object sender, EventArgs e) 4 ????????{ 5 ????????????//do something 6 ????????} 7 ????} 8 ?9 ????public partial class BasePage : Page10 ????{11 ????????/// <summary>12 ????????/// Pre_Init页面加载最早发生的事件13 ????????/// </summary>14 ????????/// <param name="sender"></param>15 ????????/// <param name="e"></param>16 ????????public void Pre_Init(object sender, EventArgs e)17 ????????{18 ????????????//检查用户登录(session/cookie)成功就继续,失败就跳转到登陆页19 ????????????//需要检查的页面就继承BasePage20 ????????????if (true)21 ????????????{22 ????????????????//继续访问23 ????????????}24 ????????????else25 ????????????{26 ????????????????//跳转登录27 ????????????}28 ????????}29 ????}
流程图
这是一个通过继承方式的解决方法,当我们页面需要权限验证的时候,只需要继承我们的带有验证方法的BasePage,而不需要验证的页面,只需要继承BasePageWithoutAuth,但是,当功能比较复杂的时候,用户登录还能用BasePage处理, 而异常处理,日志处理,缓存处理等这些可能这种方式就解决不了, 就必须在每个页面内处理完成,这就导致了很多页面重复出现了相同功能的代码
filter与AOP
AOP(Aspect Oriented Programming)面向切面编程:在不破坏类型封装的前提下,额外的添加功能.
filter即过滤器,是AOP思想在mvc中的一种具体实现,对于webform中出现的上述问题,在mvc框架中能够用filter以AOP的方式解决,
过滤器是在执行某一个方法之前,先去执行其他的某些操作,当执行完成后再确定后续动作。相当于在我们具体方法的业务逻辑之外又额外的添加了一些功能,例如权限认证,异常处理,日志记录等,我们可以把我们的业务逻辑与这些功能组合起来,而又不会被影响
filter之权限认证自定义扩展
上面说到过滤器filter可以实现请求方法前做权限校验、登录校验等,比如说只有登录的用户才可以访问这个方法,需要进行Session的校验。如果有很多的控制器中的方法都需要校验session,后期维护也是非常的不方便的,所以只需要将这种校验放在Filter中就可以了。
MVC框架自带有默认权限认证的特性[Authorize]
1 namespace System.Web.Mvc 2 { 3 ????// 4 ????// 摘要: 5 ????// ????指定对控制器或操作方法的访问只限于满足授权要求的用户。 6 ????[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] 7 ????public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter 8 ????{ 9 ????????//10 ????????// 摘要:11 ????????// ????初始化 System.Web.Mvc.AuthorizeAttribute 类的新实例。12 ????????public AuthorizeAttribute();13 14 ????????//15 ????????// 摘要:16 ????????// ????获取或设置有权访问控制器或操作方法的用户角色。17 ????????//18 ????????// 返回结果:19 ????????// ????有权访问控制器或操作方法的用户角色。20 ????????public string Roles { get; set; }21 ????????//22 ????????// 摘要:23 ????????// ????获取此特性的唯一标识符。24 ????????//25 ????????// 返回结果:26 ????????// ????此特性的唯一标识符。27 ????????public override object TypeId { get; }28 ????????//29 ????????// 摘要:30 ????????// ????获取或设置有权访问控制器或操作方法的用户。31 ????????//32 ????????// 返回结果:33 ????????// ????有权访问控制器或操作方法的用户。34 ????????public string Users { get; set; }35 36 ????????//37 ????????// 摘要:38 ????????// ????在过程请求授权时调用。39 ????????//40 ????????// 参数:41 ????????// ??filterContext:42 ????????// ????筛选器上下文,它封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。43 ????????//44 ????????// 异常:45 ????????// ??T:System.ArgumentNullException:46 ????????// ????filterContext 参数为 null。47 ????????public virtual void OnAuthorization(AuthorizationContext filterContext);48 ????????//49 ????????// 摘要:50 ????????// ????重写时,提供一个入口点用于进行自定义授权检查。51 ????????//52 ????????// 参数:53 ????????// ??httpContext:54 ????????// ????HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。55 ????????//56 ????????// 返回结果:57 ????????// ????如果用户已经过授权,则为 true;否则为 false。58 ????????//59 ????????// 异常:60 ????????// ??T:System.ArgumentNullException:61 ????????// ????httpContext 参数为 null。62 ????????protected virtual bool AuthorizeCore(HttpContextBase httpContext);63 ????????//64 ????????// 摘要:65 ????????// ????处理未能授权的 HTTP 请求。66 ????????//67 ????????// 参数:68 ????????// ??filterContext:69 ????????// ????封装有关使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 对象包括控制器、HTTP 上下文、请求上下文、操作结果和路由数据。70 ????????protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);71 ????????//72 ????????// 摘要:73 ????????// ????在缓存模块请求授权时调用。74 ????????//75 ????????// 参数:76 ????????// ??httpContext:77 ????????// ????HTTP 上下文,它封装有关单个 HTTP 请求的所有 HTTP 特定的信息。78 ????????//79 ????????// 返回结果:80 ????????// ????对验证状态的引用。81 ????????//82 ????????// 异常:83 ????????// ??T:System.ArgumentNullException:84 ????????// ????httpContext 参数为 null。85 ????????protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);86 ????}87 }
但是框架的自带东西有时候很难满足我们的需要,在此基础上我们可以继承AuthorizeAttribute,然后复写扩展(一般而言,带有virtual关键字的,都可以复写)
例如检查请求地址是否带有Account和Password的参数,值分别为Admin和123456,如果满足,则可以继续访问,否则返回指定的路径
1 ????public class CustomerAuthorizeAttribute: AuthorizeAttribute 2 ????{ 3 ????????private string LoginUrl = string.Empty; 4 ????????public CustomerAuthorizeAttribute() 5 ????????{ 6 ????????????LoginUrl = "/Home/Login"; 7 ????????} 8 ?9 ????????public CustomerAuthorizeAttribute(string loginUrl)10 ????????{11 ????????????LoginUrl = loginUrl;12 ????????}13 ????????/// <summary>14 ????????/// 请求进入具体action前,先执行OnAuthorization方法15 ????????/// </summary>16 ????????/// <param name="filterContext"></param>17 ????????public override void OnAuthorization(AuthorizationContext filterContext)18 ????????{19 ????????????//base.OnAuthorization(filterContext);20 ????????????//filterContext.HttpContext 能拿到HttpContext,意味着我们能拿到一切请求的信息21 ????????????if (filterContext.HttpContext.Request.QueryString["Account"]=="Admin"22 ????????????????&& filterContext.HttpContext.Request.QueryString["Password"] == "123456")23 ????????????{24 ????????????????return;25 ????????????}26 ????????????else27 ????????????{28 ????????????????filterContext.Result = new RedirectResult(LoginUrl);29 ????????????}30 ????????}31 32 ????}
只需要在需要权限认证的方法上加上[CustomerAuthorizeFilter]特性即可.
这就是AOP的魅力所在,只用加上一个特性,就完成了一个验证权限的功能,而且本身的业务逻辑封装没有一丝的破坏
Filter的三种注册方式
1方法注册
只给一个方法加权限认证的特性,那么就只会有特定的方法才会有权限验证
2类注册
给某个控制器加权限认证的特性,那么该控制器下所有的方法都有权限验证,但是要注意死循环,如果验证失败返回的路径也在该控制器下,那么会再次验证,然后返回再验证,一直重定向,最后重定向次数过多,页面崩溃
??[CustomerAuthorize]//类注册 ???public class HomeController : Controller ???{ ???????[CustomerAuthorize("Home/About")]//方法注册 ???????public ActionResult Index() ???????{ ???????????return View(); ???????} ??????????public ActionResult About() ???????{ ???????????ViewBag.Message = "Your application description page."; ???????????return View(); ???????} ???????public ActionResult Contact() ???????{ ???????????ViewBag.Message = "Your contact page."; ???????????return View(); ???????} ?????????//此处若是类注册,且为失败返回的路径,则会死循环 ???????public ActionResult Login() ???????{ ???????????ViewBag.Message = "Your Login page."; ???????????return View(); ???????} ???}
3全局注册
在Global.asax全局配置文件里面,有过滤器的配置文件FilterConfig.cs,在App_Start目录下,如果在这里面注册上述的权限认证特性,则所有的页面都会有权限验证
1 ????public class FilterConfig2 ????{3 ????????public static void RegisterGlobalFilters(GlobalFilterCollection filters)4 ????????{5 ????????????filters.Add(new CustomerAuthorizeAttribute());//全局注册6 ????????????filters.Add(new HandleErrorAttribute());//全局异常处理7 ????????}8 ????}
匿名登录
如果我们类注册了权限验证特性,但是在该类下面有几个需要匿名登陆的方法,那么是否意味着需要将这几个方法移到其他的控制器呢?其实不然,我们只需要给这些方法加上AllowAnonymous特性,在上述自定义特性里面先判断时候是否加了该特性即可.这里其实用什么做匿名特性都可以,只是AllowAnonymous是框架自带的一个匿名特性,就直接用了,如果想用自定义的匿名特性,再创建一个特性就可以了,什么都不需要加,只是用于标记.
1 ???if (filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute),true))2 ????????????{3 ????????????????return;4 ????????????}
出自:博客园-半路独行
原文地址:https://www.cnblogs.com/banluduxing/p/9185182.html
本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。
代码地址:https://github.com/weiweu/My-space/tree/master/Design/DecoratorPattern
.Net Mvc5Filter与权限认证扩展
原文地址:https://www.cnblogs.com/banluduxing/p/9185182.html