zoukankan      html  css  js  c++  java
  • MVC源码分析

    上一篇 其实能看到, 程序执行的过滤器, 有四种 : 

    过滤器类型

    接口

    描述

    Authorization

    IAuthorizationFilter

    此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法

    Exception

    IExceptionFilter

    用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常

    Action

    IActionFilter

    用于进入行为之前或之后的处理

    Result

    IResultFilter

    用于返回结果的之前或之后的处理

    但是默认实现它们的过滤器只有三种,分别是Authorize(授权),ActionFilter,HandleError(错误处理);各种信息如下表所示

    过滤器

    类名

    实现接口

    描述

    ActionFilter

    AuthorizeAttribute

    IAuthorizationFilter

    此类型(或过滤器)用于限制进入控制器或控制器的某个行为方法

    HandleError

    HandleErrorAttribute

    IExceptionFilter

    用于指定一个行为,这个被指定的行为处理某个行为方法或某个控制器里面抛出的异常

    自定义

    ActionFilterAttribute

    IActionFilter和IResultFilter

    用于进入行为之前或之后的处理或返回结果的之前或之后的处理

    下面就来介绍一下这几种过滤器.

    一、授权过滤器 Authorize

    1. 方式一 : Controller类中的 OnAuthorization  方法

    我们新建的控制器类里面, 都会直接或者间接继承自 Controller 类, 那么在Controller里面, 有一个 OnAuthorization 方法, 这个方法也是授权过滤器里面的.

    // 摘要: 
    //     定义授权筛选器所需的方法。
    public interface IAuthorizationFilter
    {
        // 摘要: 
        //     在需要授权时调用。
        //
        // 参数: 
        //   filterContext:
        //     筛选器上下文。
        void OnAuthorization(AuthorizationContext filterContext);
    }

    这种方式, 是不需要在 FilterConfig 文件中, 配置自己的过滤器的.

    我先建一个特性, 只要方法加上此特性, 都是不需要登录验证的.

    public class AllowLoginAttribute : Attribute
    {
    }

    里面没有任何的内容, 也不需要什么内容.

    然后就是过滤器方法了.

    public class HomeController : Controller
    {
        protected override void OnAuthorization(AuthorizationContext filterContext)
        {
            var attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowLoginAttribute), true);
            if (attrs.Count() > 0)
            {
                return;
            }
            var cookie = Request.Cookies["Login"];
            if (cookie == null || cookie.Value != "Already Login")
            {
            //正如前面解析的, 只需要给Result赋值, 就可以影响MVC走的流程 filterContext.Result
    = RedirectToAction("Login"); } }   
       //此方法会给浏览器一个 Cookie, 用来识别是否已登录身份的
       //实际使用中, 可以做成登录页面, 要求登录, 然后给Cookie和Session
    [AllowLogin]
    public ActionResult Login() { HttpCookie cookie = new HttpCookie("Login", "Already Login"); cookie.Expires = DateTime.Now.AddMinutes(3); Response.Cookies.Add(cookie); return View(); }   
       //这里就是我想要访问的页面了
    public ActionResult Index() { return View(); } }

    接下来, 我先直接访问Index页面看一下:

    直接跳转到登陆页面了, 此时, 浏览器已经得到想要的Cookie了, 这时候, 再去访问Index页面看看.

    成功访问.

    由于这种方式是写在控制器里面的, 所以就只对控制器里面的方法有效, 也就是说, 如果此时我访问一个别的控制器, 这种方法就不起作用了. 

    那么, 我是不是要在每个控制器里面写一遍? 或者我自己弄一个控制器父类, 让别的类来继承我写的类? 是不是有点太麻烦了了. 

    肿么办呢? 方法就在下面

    2. 方式二 : AuthorizeAttribute 的 OnAuthorization 方法

    方法里面的内容和上面其实是一样的, 只不过这个方法存放的位置不一样.

    但是有几个不一样的地方.

    2.1 需要在FilterConfig中注册自己的过滤器

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new MyAuthAttribute());
            filters.Add(new HandleErrorAttribute());
        }
    }

    2.2 跳转的时候, 稍有不同

    public class MyAuthAttribute : AuthorizeAttribute
    {public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowLoginAttribute), true);
            if (attrs.Count() > 0)
            {
                return;
            }
            var cookie = HttpContext.Current.Request.Cookies["Login"];
            if (cookie == null || cookie.Value != "Already Login")
            {
                filterContext.Result = new RedirectToRouteResult(
              new RouteValueDictionary(new { controller = "Home", action = "Login" })); return; } } }

    2.3 最好在Web.config文件中修改下配置.

    <system.web>
        <authentication mode="Forms">
          <forms loginUrl="~/Home/Login" timeout="2880" />
        </authentication>
    </system.web>

    我自测过了, 是可以的. 结果就不贴了, 看不出什么别的. 和上面是一样的.

    3. 方式三 : AuthorizeAttribute 的 AuthorizeCore 方法

    这个方法就简单了, 只要返回false, 就回按照上面配置文件配置的去跳转. 一般都会将这里的 OnAuthorization 和 AuthorizeCore 方法一起用.

    来看一下代码:

    public class MyAuthAttribute : AuthorizeAttribute
    {
       //在这个方法中, 我判断了用户是否已经登录 protected override bool AuthorizeCore(HttpContextBase httpContext) { bool isAuth = httpContext.User.Identity.IsAuthenticated; return isAuth; }        
       //在这个方法中, 我判断了 Action 是否需要 登录 public override void OnAuthorization(AuthorizationContext filterContext) { var attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowLoginAttribute), true); if (attrs.Count() > 0) { return; } base.OnAuthorization(filterContext); } }

    然后要修改一下HomeController控制器中的Login方法.

    [AllowLogin]
    public ActionResult Login()
    {
       //执行这个方法之后, Identity 的那里才能得到 true FormsAuthentication.SetAuthCookie("Login", false); return View(); }

    如果不想修改配置文件, 想在程序中完成自定义跳转, 可以重写 AuthorizeAttribute的 HandleUnauthorizedRequest方法, 如:

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.HttpContext.Response.Redirect("~/Home/Login");
    }

    这个方法是处理权限验证不通过后的事情.

    在使用这个过滤器的时候, 也是有两种方法的.

    1). 可以像上面那样, 在FilterConfig文件中注册进去, 这样都会从这个过滤器走一遍.

    2). 还有一种方式, 更加的灵活. 并不注册进去, 而是只在想要验证权限的方法上面加上特性, 别的方法并不受影响.

    [MyAuth]
    public ActionResult Index()
    {
        return View();
    }

    这里只会对这一个方法进行权限验证, 因为我在方法上面标注了需要验证. 对于别的方法, 却不会进行权限验证, 非常的灵活.

    目录已同步

  • 相关阅读:
    数据库学习笔记3--基本的SQL语句
    数据库学习笔记2--MySQL数据类型
    数据库学习笔记1----MySQL 5.6.21的安装和配置(setup版)
    JavaWeb学习笔记1---http协议
    Spring学习笔记18--通过工厂方法配置Bean
    Spring学习笔记17--在XML中使用SPEL
    Spring 学习笔记16---properties文件的两种方式
    Spring学习笔记15--注解Bean
    Spring4.0学习笔记1---开发环境搭建
    Installed JREs时 Standard 1.1.x VM与Standard VM的区别
  • 原文地址:https://www.cnblogs.com/elvinle/p/6296774.html
Copyright © 2011-2022 走看看