在ASP.NET MVC 3 中自定義AuthorizeAttribute時須要注意的頁面緩存問題

1、ASP.NET MVC中使用OutputCache實現服務器端頁面級緩存

    在ASP.NET MVC中,假如咱們想要將某個頁面(即某個Action)緩存在服務器端,能夠在Action上標上如下特性:web

1 [OutputCache(Duration = 10, VaryByParam = "*", Location = OutputCacheLocation.Server)] 
2 public ActionResult Login() 
3 { 
4     ViewBag.Message = "Your app description page. " + DateTime.Now.ToString(); 
5     LoginModel loginModel = new LoginModel(); 
6     ViewBag.IsValCodeVisible = IsValCodeVisible(); 
7     return View(new LoginModel()); 
8 } 

    想要使OutputCache這個特性生效,還需如下幾個條件:瀏覽器

一、Action必須是[HttpGet]。緩存

二、Web.Config中設置<system.web>/<compilation debug="false">,即應用程序的編譯條件不能是Debug。服務器

三、頁面響應Response中不能有Cookies。app

  • 1)在.NET Framework 2.0.50727.4209之前,包含Cookies的頁面響應能夠輸出緩存,源碼以下:

 

  • 2)從.NET Framework 2.0.50727.4209開始,加入了對Cookies的判斷,若是頁面響應中包含Cookies,則不輸出緩存,而是從新執行代碼。

    ASP.NET MVC 4基於.NET Framework 4或者4.5,因此一樣對Cookies做了判斷,這意味着若是Forms身份驗證的Cookie輸出方式爲HttpOnly,ide

那麼通過驗證的頁面不會輸出頁面緩存,由於每一次響應中都會帶有身份驗證票加密後生成的Cookie。this

2、爲何說盡可能不要重寫AuthorizeAttribute的OnAuthorization()方法?

    AuthorizeAttribute的源碼中的OnAuthorization()方法有這樣的註釋:加密

// Since we're performing authorization at the action level, the //authorization code runs 
// after the output caching module. In the worst case this could allow //an authorized user 
// to cause the page to be cached, then an unauthorized user would //later be served the 
// cached page. We work around this by telling proxies not to cache the //sensitive page, 
// then we hook our custom authorization code into the caching //mechanism so that we have 
// the final say on whether a page should be served from the cache. 

    大意是說這個方法中處理了服務器端頁面緩存問題,保證每一個未驗證的用戶都需通過驗證,而不是直接讀取服務器端頁面緩存。那麼什麼場景下會出現緩存問題,以及這個緩存問題的具體表現是什麼呢?下面就來演示一下。debug

一、新建ASP.NET MVC 4 Web應用程序,「項目模板」選擇「Internet應用程序」。code

二、自定義一個繼承至"AuthorizeAtrribute"的類,這個類重寫了OnAuthorization(),而且沒有針對OutputCache進行處理。

 1 public class CustomAuthorizeAttribute : AuthorizeAttribute 
 2 { 
 3     public override void OnAuthorization(AuthorizationContext filterContext) 
 4     { 
 5         if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
 6         { 
 7             HandleUnauthorizedRequest(filterContext); 
 8         } 
 9     } 
10 } 

 

三、找到Controllers/HomeController/Index,標註如下特性。

1 [HttpGet] 
2 [CustomAuthorize] 
3 [OutputCache(Duration = 30, Location = OutputCacheLocation.Server, VaryByParam = "*")] 
4 public ActionResult Index() 
5 { 
6     ViewBag.Message = "修改此模板以快速啓動你的 ASP.NET MVC 應用程序。"; 
7     return View(); 
8 }

 

四、通過以上3個步驟後,按照預期,一個用戶訪問完Home/Index後,Home/Index這個頁面會在服務器端緩存起來(Location = OutputCacheLocation.Server),後續的另外一個用戶訪問Home/Index,則會直接讀取頁面緩存,而不須要從新執行Home/Index的代碼(固然也包括身份驗證等特性的代碼)。爲了模擬兩個不一樣的用戶,下面選擇Chrome和IE兩個不一樣的瀏覽器訪問頁面。

   首先打開Chrome瀏覽器,訪問Account/Login,輸入帳號密碼進行登陸,而後訪問首頁Home/Index,顯示以下:

 

   

    接着打開IE瀏覽器,直接訪問Home/Index。若是沒有頁面緩存,這時候是不能直接打開頁面的,由於Home/Index已經標註了[CustomAuthorize],是須要身份驗證的,但由於有了頁面緩存,因此服務器直接將第一次在Chrome瀏覽器訪問Home/Index時在服務器留下的緩存發送給IE瀏覽器的請求。頁面顯示以下:

 

   

ASP.NET保存Cookie的方式默認不是HttpOnly,不會在每次頁面響應中帶有Cookie,服務器端的OutputCache能夠生效,因此這種狀況下重寫AuthorizeAttribute的OnAuthorization()就會有問題。

相關文章
相關標籤/搜索