MVC源碼分析 - Authorize授權過濾器


上一篇 其實能看到, 程序執行的過濾器, 有四種 : 

過濾器類型

接口

描述

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();
}

這里只會對這一個方法進行權限驗證, 因為我在方法上面標注了需要驗證. 對於別的方法, 卻不會進行權限驗證, 非常的靈活.

目錄已同步


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM