使用Azure的缓存(.NET MVC3应用程序)时,我为什么不能结合[授权]和[的OutputCache]属性? [英] Why can't I combine [Authorize] and [OutputCache] attributes when using Azure cache (.NET MVC3 app)?

查看:157
本文介绍了使用Azure的缓存(.NET MVC3应用程序)时,我为什么不能结合[授权]和[的OutputCache]属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Windows Azure中的 Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider 作为的OutputCache提供商的MVC3应用程序。下面是相关操作方法:

Using Windows Azure's Microsoft.Web.DistributedCache.DistributedCacheOutputCacheProvider as the outputCache provider for an MVC3 app. Here is the relevant action method:

[ActionName("sample-cached-page")]
[OutputCache(Duration = 300, VaryByCustom = "User", 
    Location = OutputCacheLocation.Server)]
[Authorize(Users = "me@mydomain.tld,another@otherdomain.tld")]
public virtual ActionResult SampleCachedPage()
{
    return View();
}

从Web浏览器中加载这个观点时,我得到以下异常:

I get the following exception when loading this view from a web browser:

System.Configuration.Provider.ProviderException: When using a custom output cache provider like 'DistributedCache', only the following expiration policies and cache features are supported: file dependencies, absolute expirations, static validation callbacks and static substitution callbacks.

System.Configuration.Provider.ProviderException: When using a custom output cache provider like 'DistributedCache', only the following expiration policies and cache features are supported:  file dependencies, absolute expirations, static validation callbacks and static substitution callbacks.
   at System.Web.Caching.OutputCache.InsertResponse(String cachedVaryKey, CachedVary cachedVary, String rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp)
   at System.Web.Caching.OutputCacheModule.OnLeave(Object source, EventArgs eventArgs)
   at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

如果我删除[授权]属性,视图缓存正如所预料的。这是否意味着我不能把[的OutputCache]上必须有[授权]的操作方法?或者,我需要重写AuthorizeAttribute与使用静态验证回调方法用于缓存的自定义实现?

If I remove the [Authorize] attribute, the view caches as would be expected. Does this mean I cannot put [OutputCache] on an action method that must have [Authorize]? Or, do I need to override AuthorizeAttribute with a custom implementation that uses a static validation callback method for the cache?

更新1

在埃文的回答,我测试了IIS防爆preSS上述操作方法(天青外)。下面是我重写了VaryByCustom是=用户上的OutputCache属性属性:

After Evan's answer, I tested the above action method in IIS Express (outside of Azure). Here is my override for the VaryByCustom = "User" property on the OutputCache attribute:

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    return "User".Equals(custom, StringComparison.OrdinalIgnoreCase)
        ? Thread.CurrentPrincipal.Identity.Name
        : base.GetVaryByCustomString(context, custom);
}

当我访问样本缓存页面me@mydomain.tld,页面的输出被缓存,且视图显示此页于12/31/2011 11:06缓存: 12 AM(UTC)。如果我再注销并登录为another@otherdomain.tld和访问的页面,它会显示此页于12/31/2011 11:06缓存: 38 AM(UTC)。重新登录作为me@mydomain.tld和重温网页导致缓存,显示此页面是在12/31/2011 11:06缓存: 12 AM(UTC)了。输入/输出企图进一步的迹象表明,不同的输出被缓存和放大器;返回的根据用户

When I visit the sample cached page as me@mydomain.tld, the output of the page is cached, and the view displays "This page was cached at 12/31/2011 11:06:12 AM (UTC)". If I then sign out and sign in as another@otherdomain.tld and visit the page, it displays "This page was cached at 12/31/2011 11:06:38 AM (UTC)". Signing back in as me@mydomain.tld and revisiting the page causes the cache to display "This page was cached at 12/31/2011 11:06:12 AM (UTC)" again. Further sign in/out attempts show that different output is being cached & returned depending on the user.

这是导致我相信,输出是基于用户,这是我的VaryByCustom是=用户的设置和功放的意向分别缓存;覆盖。的问题是,它不与天青的分布式缓存提供工作。埃文,你不回答关于只缓存公开内容仍然站立?

This is leading me to believe that the output is being cached separately based on the user, which is the intention with my VaryByCustom = "User" setting & override. The problem is that it doesn't work with Azure's distributed cache provider. Evan, does you answer about only caching public content still stand?

更新2

我挖出源,发现出的现成的AuthorizeAttribute事实上确实有一个非静态验证回调。下面是摘自 OnAuthorization

I dug up the source, and found that the out-of-box AuthorizeAttribute does in fact have a non-static validation callback. Here is an excerpt from OnAuthorization:

if (AuthorizeCore(filterContext.HttpContext)) {
    // ** IMPORTANT **
    // Since we're performing authorization at the action level, the authorization code runs
    // after the output caching module. In the worst case this could allow an authorized user
    // to cause the page to be cached, then an unauthorized user would later be served the
    // cached page. We work around this by telling proxies not to cache the sensitive page,
    // then we hook our custom authorization code into the caching mechanism so that we have
    // the final say on whether a page should be served from the cache.

    HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
    cachePolicy.SetProxyMaxAge(new TimeSpan(0));
    cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
}
else {
    HandleUnauthorizedRequest(filterContext);
}

CacheValidationHandler 代表缓存验证,以受保护的虚拟HttpValidationStatus OnCacheAuthorization(HttpContextBase),这当然也不是一成不变的。其中一个原因为什么它不是一成不变的,因为,作为重要评论指出上面,它调用受保护的虚拟BOOL AuthorizeCore(HttpContextBase)

CacheValidationHandler delegates the cache validation to protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase), which of course is not static. One reason why it is not static is because, as noted in the IMPORTANT comment above, it invokes protected virtual bool AuthorizeCore(HttpContextBase).

为了从静态缓存验证回调方法做任何的AuthorizeCore逻辑,就需要知道AuthorizeAttribute实例的用户和角色属性。但是似乎没有被堵塞在一个简单的方法,我将不得不重写OnAuthorization把这些值2成的HttpContext(Items集合?),然后覆盖OnCacheAuthorization让他们回来。但闻起来很脏。

In order to do any of the AuthorizeCore logic from a static cache validation callback method, it would need to know the Users and Roles properties of the AuthorizeAttribute instance. However there doesn't seem to be an easy way to plug in. I would have to override OnAuthorization to put these 2 values into the HttpContext (Items collection?) and then override OnCacheAuthorization to get them back out. But that smells dirty.

如果我们小心使用VaryByCustom是=用户属性中的OutputCache属性,可我们只是覆盖OnCacheAuthorization总是返回HttpValidationStatus.Valid?当操作方法没有一个OutputCache属性,我们就不需要担心这个回调曾经被调用,是否正确?如果我们这样做有没有VaryByCustom是=用户一个OutputCache属性,那么它应该是显而易见的页面可以返回任何缓存的版本,无论哪个用户请求创建的缓存副本。多么危险是什么?

If we are careful to use the VaryByCustom = "User" property in the OutputCache attribute, can we just override OnCacheAuthorization to always return HttpValidationStatus.Valid? When the action method does not have an OutputCache attribute, we would not need to worry about this callback ever being invoked, correct? And if we do have an OutputCache attribute without VaryByCustom = "User", then it should be obvious that the page could return any cached version regardless of which user request created the cached copy. How risky is this?

推荐答案

缓存操作之前发生。你可能会需要自定义您的授权机制来处理缓存的方案。

Caching happens before the Action. You will likely need to customize your authorization mechanics to handle cache scenarios.

检查出的问题我张贴了一段时间回来 - <一个href=\"http://stackoverflow.com/questions/8567358/mvc-custom-authentication-authorization-and-roles-implementation\">MVC自定义身份验证,授权和角色实现。

Check out a question I posted a while back - MVC Custom Authentication, Authorization, and Roles Implementation.

我想会帮助你的部分是一个定制的授权属性谁与缓存 OnAuthorize()法的交易。

The part I think would help you is a custom Authorize Attribute who's OnAuthorize() method deals with caching.

下面是一个例子code座:

Below is a code block for example:

/// <summary>
/// Uses injected authorization service to determine if the session user 
/// has necessary role privileges.
/// </summary>
/// <remarks>As authorization code runs at the action level, after the 
/// caching module, our authorization code is hooked into the caching 
/// mechanics, to ensure unauthorized users are not served up a 
/// prior-authorized page. 
/// Note: Special thanks to TheCloudlessSky on StackOverflow.
/// </remarks>
public void OnAuthorization(AuthorizationContext filterContext)
{
    // User must be authenticated and Session not be null
    if (!filterContext.HttpContext.User.Identity.IsAuthenticated || filterContext.HttpContext.Session == null)
        HandleUnauthorizedRequest(filterContext);
    else {
        // if authorized, handle cache validation
        if (_authorizationService.IsAuthorized((UserSessionInfoViewModel)filterContext.HttpContext.Session["user"], _authorizedRoles)) {
            var cache = filterContext.HttpContext.Response.Cache;
            cache.SetProxyMaxAge(new TimeSpan(0));
            cache.AddValidationCallback((HttpContext context, object o, ref HttpValidationStatus status) => AuthorizeCache(context), null);
        }
        else
            HandleUnauthorizedRequest(filterContext);             
    }
}

/// <summary>
/// Ensures that authorization is checked on cached pages.
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public HttpValidationStatus AuthorizeCache(HttpContext httpContext)
{
    if (httpContext.Session == null)
        return HttpValidationStatus.Invalid;
    return _authorizationService.IsAuthorized((UserSessionInfoViewModel) httpContext.Session["user"], _authorizedRoles) 
        ? HttpValidationStatus.Valid 
        : HttpValidationStatus.IgnoreThisRequest;
}

这篇关于使用Azure的缓存(.NET MVC3应用程序)时,我为什么不能结合[授权]和[的OutputCache]属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆