zoukankan      html  css  js  c++  java
  • .Net Mvc5Filter与权限认证扩展

    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 : Page
    10     {
    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             //需要检查的页面就继承BasePage
    20             if (true)
    21             {
    22                 //继续访问
    23             }
    24             else
    25             {
    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

    但是框架的自带东西有时候很难满足我们的需要,在此基础上我们可以继承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             else
    27             {
    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 FilterConfig
    2     {
    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

  • 相关阅读:
    NetworkInterface网速监测
    动态编译
    JSON C# Class Generator
    Cookie中的HttpOnly
    webapi session
    没有为扩展名“.html”注册的生成提供程序
    转 C# 使用openssl
    openssl jia adress
    扩展JS
    bootstrap 模态
  • 原文地址:https://www.cnblogs.com/banluduxing/p/9185182.html
Copyright © 2011-2022 走看看