Этот код существует, чтобы позволить вам одновременно использовать [OutputCache] и [Authorize] для действия без риска кэширования ответа, который был сгенерирован для авторизованного пользователя и передан пользователю, который не авторизован.
Вот комментарий исходного кода от AuthorizeAttribute.cs:
Так как мы выполняем авторизацию
на уровне действий, авторизация
код запускается после кэширования вывода
модуль. В худшем случае это могло
разрешить авторизованному пользователю вызывать
страница для кэширования, затем
неавторизованный пользователь позже будет
обслуживал кэшированную страницу. Мы работаем вокруг
это говорит прокси не кэшировать
чувствительная страница, то мы подключаем
пользовательский код авторизации в
механизм кэширования, так что мы имеем
последнее слово о том, должна ли быть страница
подается из кеша.
Так что же делает этот атрибут? Сначала он отключает прокси-кэширование этого ответа, поскольку прокси-серверы не могут правильно определить, какие пользователи имеют или не авторизованы для его просмотра. И если прокси-сервер отправляет ответ неавторизованному пользователю, это очень плохо.
А как насчет AddValidationCallback? В ASP.NET модуль кэширования вывода перехватывает события, которые запускаются до обработчика HTTP. Поскольку MVC на самом деле является просто специальным обработчиком HTTP, это означает, что если модуль кэширования вывода обнаружит, что этот ответ уже был кэширован, то модуль просто будет обслуживать ответ непосредственно из кэша, вообще не проходя через конвейер MVC. Это также может быть очень плохой вещью, если кэш вывода служит ответом неавторизованному пользователю.
Теперь подробнее рассмотрим CacheValidateHandler :
private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) {
validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
}
// This method must be thread-safe since it is called by the caching module.
protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext) {
if (httpContext == null) {
throw new ArgumentNullException("httpContext");
}
bool isAuthorized = AuthorizeCore(httpContext);
return (isAuthorized) ? HttpValidationStatus.Valid : HttpValidationStatus.IgnoreThisRequest;
}
Это фактически просто связывает метод AuthorizeCore с кэшированным ответом. Когда модуль кэша вывода обнаруживает совпадение, он повторно запускает метод AuthorizeCore, чтобы убедиться, что текущему пользователю действительно разрешено видеть кэшированный ответ. Если AuthorizeCore возвращает true, он обрабатывается как попадание в кэш (HttpValidationStatus.Valid), и ответ подается из кэша без прохождения через конвейер MVC. Если AuthorizeCore возвращает значение false, это считается ошибкой кэша (HttpValidationStatus.IgnoreThisRequest), и конвейер MVC работает как обычно, чтобы сгенерировать ответ.
Кроме того, поскольку делегат создается для AuthorizeCore (таким образом, захватывая конкретный экземпляр AuthorizeAttribute) и сохраняется в статическом кэше, именно поэтому все типы подклассов AuthorizeAttribute должны быть поточно-ориентированными.