Когда `PostAuthenticateRequest` получает выполнение?

Это мой файл 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;
        }
    }
}

Когда PostAuthenticateRequest получает выполнение?

Ответ 1

В соответствии с документацией:

Происходит, когда модуль безопасности имеет установил личность пользователя.

...

Событие 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;
    }
}

Теперь украсьте свои контроллеры/действия атрибутом [MyAuthorize]:

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

Ответ 2

Если вы поместите свой код в PostAuthenticateRequest, вы можете получить много раз за запрос, поскольку каждый ресурс, такой как изображения и таблицы стилей, на которые ссылается ваша страница, будет вызывать это событие, поскольку они рассматриваются как отдельные запросы.

Если вы ответите с ответом @Darin, атрибут AuthorizeAttribute не будет отображать действие, когда isAuthorized возвращает false, но люди могут нуждаться в его визуализации в любом случае, даже если его общедоступная страница (неограниченный доступ), вы можете захотеть показать "Отображаемое имя" сохраняется в части userData файла authTicket.

Для этого я рекомендую загрузить authCookie в ActionFilterAttribute (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 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());
    }

Таким образом вам также не придется заполнять все ваши действия атрибутом.