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

2024-03-30

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

[ActionName("sample-cached-page")]
[OutputCache(Duration = 300, VaryByCustom = "User", 
    Location = OutputCacheLocation.Server)]
[Authorize(Users = "[email protected] /cdn-cgi/l/email-protection,[email protected] /cdn-cgi/l/email-protection")]
public virtual ActionResult SampleCachedPage()
{
    return View();
}

从网络浏览器加载此视图时出现以下异常:

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?

Update 1

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

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

当我访问示例缓存页面时[电子邮件受保护] /cdn-cgi/l/email-protection,页面的输出被缓存,并且视图显示“此页面于 12/31/2011 11:06 被缓存:12AM (UTC)”。如果我随后注销并以身份登录[电子邮件受保护] /cdn-cgi/l/email-protection访问该页面,显示“此页面已于 12/31/2011 11:06 缓存:38AM (UTC)”。重新登录为[电子邮件受保护] /cdn-cgi/l/email-protection重新访问该页面会导致缓存显示“此页面已于 12/31/2011 11:06 缓存:12再次尝试“AM (UTC)”。进一步的登录/注销尝试显示,根据用户的不同,正在缓存和返回不同的输出。

这让我相信输出是根据用户单独缓存的,这就是我的 VaryByCustom =“User”设置和覆盖的意图。问题是它不能与 Azure 的分布式缓存提供程序一起使用。埃文,您关于仅缓存公共内容的回答仍然有效吗?

Update 2

我挖掘了源代码,发现开箱即用的 AuthorizeAttribute 实际上确实有一个非静态验证回调。这是摘录自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将缓存验证委托给protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase),这当然不是静态的。它不是静态的原因之一是,正如上面重要注释中所述,它调用protected virtual bool AuthorizeCore(HttpContextBase).

为了通过静态缓存验证回调方法执行任何 AuthorizeCore 逻辑,需要了解 AuthorizeAttribute 实例的 Users 和 Roles 属性。然而,似乎没有一种简单的插入方法。我必须重写 OnAuthorization 将这两个值放入 HttpContext (Items 集合?),然后重写 OnCacheAuthorization 将它们取出。但那味道很脏。

如果我们小心地在 OutputCache 属性中使用 VaryByCustom = "User" 属性,我们是否可以重写 OnCacheAuthorization 以始终返回 HttpValidationStatus.Valid?当操作方法没有 OutputCache 属性时,我们不需要担心调用此回调,对吗?如果我们确实有一个没有 VaryByCustom = "User" 的 OutputCache 属性,那么很明显,无论哪个用户请求创建了缓存副本,页面都可以返回任何缓存版本。这有多危险?


缓存发生在操作之前。您可能需要自定义授权机制来处理缓存场景。

看看我不久前发布的一个问题 -MVC 自定义身份验证、授权和角色实现 https://stackoverflow.com/questions/8567358/mvc-custom-authentication-authorization-and-roles-implementation.

我认为对您有帮助的部分是自定义授权属性OnAuthorize()方法处理缓存。

下面是一个代码块示例:

/// <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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Azure 缓存(.NET MVC3 应用程序)时,为什么无法组合 [Authorize] 和 [OutputCache] 属性? 的相关文章

  • .NET MVC - 一次提交相同类型的多个模型

    我认为我有一个非常简单的场景 但似乎无法掌握如何在 NET 的 MVC 框架中做到这一点 最简单地说 这是一种对人员进行排名的形式 我希望将每个人的姓名及其姓名旁边的文本框列在一页上 Razor Html 如下所示 using Html B
  • 如何在部署作业期间设置 XML 转换的环境名称?

    好的 伙计们 给 Azure多级管道尝试一下 但不太幸运地使用部署作业进行 xml 转换 Update 这没有使用 Azure DevOps 中的经典部署 发布 UI 到目前为止我所做的 从构建过程中删除转换 尝试一次构建并随处部署 通过删
  • Laravel:运行队列:在 Windows Azure Web App 上连续监听

    我觉得问这个问题有点傻 但我似乎无法在互联网上找到这个问题的答案 经过几个小时的搜索后 我发现在 Linux 服务器上 您使用 Supervisor 在您的网站上连续运行 php artisanqueue listen 无论有或没有守护进程
  • 在 mvc 中对远程验证的成功响应执行一些操作

    我正在使用远程验证来检查我的 asp net mvc 3 应用程序 C 注册期间用户名的可用性 我使用 MVC 远程属性验证 Remote IsUserNameAvailable User public string UserName ge
  • ASP.NET MVC4 CustomErrors DefaultRedirect 被忽略

    我有一个 MVC 4 应用程序 使用自定义 HandleErrorAttribute 仅处理自定义异常 我想拦截默认的 404 和其他非 500 错误页面 并用更有吸引力的内容替换它们 为此 我将以下内容添加到我的 Web config 中
  • 用于 mvc3 日期格式和日期验证的文本框

    我决定开始使用 MVC 3 并且在尝试将我的一个 Web 应用程序重做为 MVC3 时遇到了这个问题 我的项目是这样设置的 public class Project public int ProjectID get set Required
  • 如何在 Web 应用程序中使用 Javascript 安全地访问 Windows Azure 移动服务?

    我需要一本 web javascript 安全入门书 根据如何使用 Windows Azure 移动服务的 HTML JavaScript 客户端 http www windowsazure com en us develop mobile
  • 节点项目的 Azure git 部署失败

    我正在尝试将我的项目部署到azure 它正在失败 这些是我采取的步骤 git init git config core longpaths true git add git commit m initial commit 所有这些都有效 我
  • Azure 网站中的 404 处理

    我在 Azure 上有一个 MVC 网站 我已经编写了一个控制器操作来代表资源 该操作应该返回 HTTP 404 但正文内容应该是一些 HTML 我在其中解释了 404 的原因 这是作为一个标准操作实现的 该操作设置Response Sta
  • 尝试将 Asp.Net Memebership 数据库部署到 SQL Azure

    我一直在尝试让 ASP net 会员服务提供商与托管在 SQL Azure 中的其余数据库配合使用 我已针对数据库运行适当的 SQL Azure 特定脚本来进行设置 这些脚本可从 Microsoft 获取 http archive msdn
  • 目标中的 clr.dll 版本与构建的 mscordacwks.dll 版本不匹配

    我正在使用 NET Framework 4 0 开发 ASP NET MVC 3 应用程序 当我去调试我的应用程序时 我收到消息 无法附加到应用程序 webdev webserver 目标中的 clr dll 版本与构建 mcordacwk
  • Azure Graph API 身份验证_MissingOrMalformed

    我正在使用 Azure Graph API 从 Azure AD 导入用户 在天蓝色门户中 我添加了多个应用程序 我从 protal 获取 clientId tenantId 并创建一个有效期为一年的密钥 使用这些值 我创建一个 acces
  • 关于JSON和序列化的问题

    我的视图模型有一个强类型视图 其中包含一个对象 Person 和一个技能列表 人是很直率的 我像这样使用 Html Helpers Html TextBoxFor m gt m Person FirstName 我提交表格并得到我想要的 问
  • ASP.NET MVC 3,如何正确制作主题

    我正在寻找有关如何以最佳方式在 MVC 3 中实现 主题 的输入 我想需要一个自定义视图引擎来负责定位视图文件等 我还希望主题系统是可扩展的 这样 如果它只是其中一个视图 我想更改其他视图 但仍使用默认值 有点像 Orchard 项目吗 想
  • Azure CloudTable 线程安全吗?

    我正在使用 Storage SDK 2 0 从不同线程 ASP NET 应用程序 写入 Azure 表存储 Is 云表 object 线程安全 我是否可以仅初始化 CloudStorageAccount CloudTableClient 和
  • 如何在 Azure 逻辑应用中解析 Excel 电子表格

    我需要使用 Azure 逻辑应用从 Excel 电子表格中解析和提取列信息 我已经为我的逻辑应用程序设置了从 Outlook 检索最新未读电子邮件的功能 此外 我的逻辑应用程序执行 FOR EACH 来读取所有附件 来自未读电子邮件 并确保
  • Azure SQL 数据仓库 DWU 与 Azure SQL DTU

    我正在考虑从 Azure SQL 迁移到 Azure SQL 数据仓库 它似乎提供了我们需要的一些功能 但是价格是从小规模开始的一个问题 100 DWU 数据仓库的价格相当高 521 月 https azure microsoft com
  • 删除实例后,Azure 云服务变得无响应?

    我的 Azure 云服务 当它从 3 个实例缩减到 2 个实例时 我的网站会变得无响应几分钟 我的印象是 我的现有实例将保持不变 除了那些被删除的实例 并且我的网站将继续正常运行 我可能是错的 这是正常行为吗 当您从 2 个实例缩减到 1
  • 如何排列表格中的项目 - MVC3 视图 (Index.cshtml)

    我想使用 ASP NET MVC3 显示特定类型食品样本中存在的不同类型维生素的含量 如何在我的视图 Index cshtml 中显示它 an example 这些是我的代码 table tr th th foreach var m in
  • Azure 管理 API 返回 500 内部服务器错误

    我通过此请求从 Azure REST 管理 API 返回 500 内部服务器错误 为什么 X509Certificate cert X509Certificate2 CreateFromCertFile cert path string u

随机推荐