.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


免責聲明!

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



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