当`PostAuthenticateRequest`被执行时?

Jal*_*lal 13 .net c# asp.net asp.net-mvc-2

这是我的Global.asax.cs档案:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

什么时候PostAuthenticateRequest执行?

Dar*_*rov 20

根据文件:

在安全模块已建立用户标识时发生.

...

在AuthenticateRequest事件发生后引发PostAuthenticateRequest事件.订阅PostAuthenticateRequest事件的功能可以访问PostAuthenticateRequest处理的任何数据.

这是ASP.NET页面生命周期.

但是因为您的问题是用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在用[MyAuthorize]属性装饰你的控制器/动作:

[MyAuthorize]
public ActionResult Foo()
{
    // if you got here the User property will be the custom
    // principal you injected in the authorize attribute
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • @zespri每页可多次调用PostAuthenticateRequest事件.使用自定义授权属性可确保每个请求只调用一次代码. (6认同)
  • 为什么建议在所有控制器上应用过滤器,如果在事件处理程序的单个位置进行更改似乎更清晰?收益是多少? (4认同)

Joa*_*eme 9

如果您将代码放在PostAuthenticateRequest上,则每个请求可能会多次命中,因为页面上引用的图像和样式表等每个资源都会触发此事件,因为它们被视为单独的请求.

如果你使用@ Darin的答案,当isAuthorized返回false时,AuthorizeAttribute将不会呈现操作,但是人们可能无论如何都需要呈现它,即使它是一个公共页面(不受限制的访问)你可能想要显示"显示名称" "保存在authTicket的userData部分.

为此,我建议在ActionFilterAttribute(AuthenticationFilter)上加载authCookie:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在global.asax.cs上

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new LoadCustomAuthTicket());
    }
Run Code Online (Sandbox Code Playgroud)

这样,您也不必使用该属性填充所有操作.