首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么在使用Azure缓存(.NET MVC3应用程序)时无法组合[Authorize]和[OutputCache]属性?

为什么在使用Azure缓存(.NET MVC3应用程序)时无法组合[Authorize]和[OutputCache]属性?
EN

Stack Overflow用户
提问于 2011-12-31 02:22:39
回答 3查看 6.6K关注 0票数 21

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

代码语言:javascript
复制
[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浏览器加载此视图时,出现以下异常:

代码语言:javascript
复制
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)

如果我删除Authorize属性,视图将按照预期进行缓存。这是否意味着我不能将OutputCache放在必须具有Authorize的操作方法上?或者,我是否需要使用对缓存使用静态验证回调方法的自定义实现来覆盖AuthorizeAttribute?

更新1

在Evan的回答之后,我在IIS Express中(Azure之外)测试了上面的操作方法。下面是我对OutputCache属性的VaryByCustom = "User“属性的覆盖:

代码语言:javascript
复制
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访问示例缓存页面时,页面的输出被缓存,视图显示"This page is cached at 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)”。进一步的登录/注销尝试显示,根据用户的不同,缓存和返回不同的输出。

这让我相信输出是根据用户单独缓存的,这就是我的VaryByCustom = " user“设置& override的目的。问题是它不能与Azure的分布式缓存提供程序一起工作。Evan,你的答案是只缓存公共内容仍然有效吗?

更新2

我找出了源代码,发现开箱即用的AuthorizeAttribute确实有一个非静态的验证回调。以下是OnAuthorization的摘录

代码语言:javascript
复制
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将缓存验证委托给protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase),它当然不是静态的。它不是静态的原因之一是,正如上面的重要注释所指出的,它调用了protected virtual bool AuthorizeCore(HttpContextBase)

为了从静态缓存验证回调方法执行任何AuthorizeCore逻辑,它需要知道AuthorizeAttribute实例的用户和角色属性。然而,似乎没有一种简单的方法来插入。我必须重写OnAuthorization才能将这两个值放入HttpContext (Items集合?)然后重写OnCacheAuthorization把它们弄回来。但那闻起来很脏。

如果我们小心地在OutputCache属性中使用VaryByCustom = "User“属性,我们是否可以只覆盖OnCacheAuthorization以始终返回HttpValidationStatus.Valid?当操作方法没有OutputCache属性时,我们就不需要担心这个回调被调用了,对吗?如果我们有一个没有VaryByCustom = " user“的OutputCache属性,那么很明显,页面可以返回任何缓存的版本,而不管是哪个用户请求创建了缓存的副本。这有多大的风险?

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8682635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档