2011-05-10 45 views
13

這是我Global.asax.cs文件:當`PostAuthenticateRequest`得到執行時?

public class MvcApplication : System.Web.HttpApplication 
{ 
    public static void RegisterRoutes(RouteCollection routes) 
    { 
     ... 
    } 

    protected void Application_Start() 
    { 
     this.PostAuthenticateRequest += new EventHandler(MvcApplication_PostAuthenticateRequest); 
    } 

    // This method never called by requests... 
    protected void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e) 
    { 
     HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; 

     if (authCookie != null) 
     { 
      FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
      var identity = new GenericIdentity(authTicket.Name, "Forms"); 
      var principal = new GenericPrincipal(identity, new string[] { }); 
      Context.User = principal; 
     } 
    } 
} 

PostAuthenticateRequest得到執行?

回答

20

按照documentation

當安全模塊具有 建立用戶的身份出現。

...

的PostAuthenticateRequest事件是 發生了AuthenticateRequest 事件後引發。功能, 訂閱該 PostAuthenticateRequest事件可以 訪問由 的PostAuthenticateRequest處理的任何數據。

而這裏是ASP.NET Page Life Cycle

但是因爲你的問題是用ASP.NET MVC標記的,所以我強烈建議你在自定義[Authorize]屬性中執行此操作,而不是使用此事件。例如:

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var isAuthorized = base.AuthorizeCore(httpContext); 
     if (isAuthorized) 
     { 
      var authCookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName]; 
      if (authCookie != null) 
      { 
       var authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
       var identity = new GenericIdentity(authTicket.Name, "Forms"); 
       var principal = new GenericPrincipal(identity, new string[] { }); 
       httpContext.User = principal; 
      } 
     } 
     return isAuthorized; 
    } 
} 

現在裝飾你的控制器/與[MyAuthorize]屬性動作:

[MyAuthorize] 
public ActionResult Foo() 
{ 
    // if you got here the User property will be the custom 
    // principal you injected in the authorize attribute 
    ... 
} 
+4

你爲什麼要對所有控制器推薦應用過濾器,當它看起來乾淨多有在事件處理程序的單一位置的變化?收益是多少? – 2011-11-21 23:49:28

+1

對於這個例子,它可能會更有意義,以取代var identity = new GenericIdentity(authTicket.Name,「Forms」); var identity = new FormsIdentity(authTicket); – 2012-03-28 02:39:47

+6

@zespri PostAuthenticateRequest事件可能每頁調用多次。使用自定義授權屬性可確保您的代碼僅在每個請求中被調用一次。 – Mark 2012-03-29 00:41:35

9

如果你把你的代碼上PostAuthenticateRequest你可能會擊中每個請求多次,每一個資源,如圖像和樣式在您的頁面上引用的工作表將觸發此事件,因爲它們被視爲單獨的請求。

如果您一起去@ Darin的回答,AuthorizeAttribute將不渲染操作時isAuthorized返回false,但人們可能需要的是反正渲染,即使它是一個公共頁面(無限制訪問),你可能想顯示保存在authTicket的userData部分上的「顯示名稱」。

對於這一點,我建議上ActionFilterAttribute加載authCookie(AuthenticationFilter):

public class LoadCustomAuthTicket : ActionFilterAttribute, IAuthenticationFilter 
{ 
    public void OnAuthentication(AuthenticationContext filterContext) 
    { 
     if (!filterContext.Principal.Identity.IsAuthenticated) 
      return; 

     HttpCookie authCookie = filterContext.HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName]; 

     if (authCookie == null) 
      return; 

     FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value); 
     var identity = new GenericIdentity(authTicket.Name, "Forms"); 
     var principal = new GenericPrincipal(identity, new string[] { }); 

     // Make sure the Principal's are in sync. see: https://www.hanselman.com/blog/SystemThreadingThreadCurrentPrincipalVsSystemWebHttpContextCurrentUserOrWhyFormsAuthenticationCanBeSubtle.aspx 
     filterContext.Principal = filterContext.HttpContext.User = System.Threading.Thread.CurrentPrincipal = principal; 

    } 
    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) 
    { 
     //This method is responsible for validating the current principal and permitting the execution of the current action/request. 
     //Here you should validate if the current principle is valid/permitted to invoke the current action. (However I would place this logic to an authorization filter) 
     //filterContext.Result = new RedirectToRouteResult("CustomErrorPage",null); 
    } 
} 

而上的global.asax.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
    { 
     filters.Add(new LoadCustomAuthTicket()); 
    } 

這樣,你也就不會有填充你的所有動作與屬性。

+0

如果兩個操作都應用於某個操作,此操作是否會篩選自定義授權屬性的腳趾? – 2015-03-18 14:02:28

+0

另外,是否有辦法確保該屬性在授權屬性之前執行?理想情況下,我們只會在任何屬性執行之前在一個位置加載cookie。 – 2015-03-18 14:04:54

+0

找到一些相關的和有趣的操作信息順序。 http://stackoverflow.com/questions/6561883/in-what-order-are-filters-executed-in-asp-net-mvc – 2015-03-18 14:46:09

相關問題