このコードは、許可されたユーザーに対して生成された応答がキャッシュされ、許可されていないユーザーに提供されるというリスクを冒すことなく、アクションに [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 をサブクラス化するすべての型はスレッドセーフでなければなりません。