ASP.NET MVC 缓存 - 登录用户被缓存

ASP.NET MVC Caching - Logged-in user gets cached

我有一个 ASP.NET MVC 应用程序,我在其中实现了自定义缓存过滤器,代码如下:

public class NonAuthenticatedOnlyCacheAttribute : OutputCacheAttribute
{
    public NonAuthenticatedOnlyCacheAttribute()
    {
        Duration = 600;  /*default cache time*/
    }

    private bool _partialView;
    public bool PartialView
    {
        get { return _partialView; }
        set
        {
            _partialView = value;
            if (_partialView)
            {
                VaryByCustom = "user";
            }
        }
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        if (PartialView) OnCachePartialEnabled(filterContext);
        else OnCacheEnabled(filterContext);

        base.OnResultExecuting(filterContext);
    }

    private OutputCacheLocation? originalLocation;
    private int? _prevDuration;

    protected void OnCachePartialEnabled(ResultExecutingContext filterContext)
    {
        var httpContext = filterContext.HttpContext;

        if (!_prevDuration.HasValue) _prevDuration = Duration;
        Duration = httpContext.User.Identity.IsAuthenticated ? 1 : _prevDuration.Value;
    }

    protected void OnCacheEnabled(ResultExecutingContext filterContext)
    {
        var httpContext = filterContext.HttpContext;

        if (httpContext.User.Identity.IsAuthenticated)
        {
            // it's crucial not to cache Authenticated content
            originalLocation = originalLocation ?? Location;
            Location = OutputCacheLocation.None;
        }
        else
        {
            Location = originalLocation ?? Location;
        }

        // this smells a little but it works
        httpContext.Response.Cache.AddValidationCallback(IgnoreAuthenticated, null);
    }

    // This method is called each time when cached page is going to be
    // served and ensures that cache is ignored for authenticated users.
    private void IgnoreAuthenticated(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
        validationStatus = context.User.Identity.IsAuthenticated
          ? HttpValidationStatus.IgnoreThisRequest
          : HttpValidationStatus.Valid;
    }
}

我面临的问题是,即使我没有为经过身份验证的用户缓存页面,有时我也会看到其他一些经过身份验证的用户的缓存页面。这种情况很少发生且随机发生。

如果我通过这个调试,它工作得很好,但当它出现在实时站点上时就不行了。 我还看到,经过身份验证的用户的 cookie (".AspNet.ApplicationCookie") 也会在浏览器中创建。 (这是否意味着输出缓存也在缓存响应 cookie?) 如果我删除此 cookie,那么用户将被注销,这很明显。

在Global.asax中,我有以下代码:

public override string GetVaryByCustomString(HttpContext context, string value)
    {
        if (value.Equals("culture") || value.Equals("user"))
        {
            var customString = Thread.CurrentThread.CurrentUICulture.Name;
            if (context.User.Identity.IsAuthenticated)
            {
                customString = $"{context.User.Identity.Name}-{customString}";
            }
            return customString;
        }
        return base.GetVaryByCustomString(context, value);
    }

并且在控制器上,缓存了以下属性

[NonAuthenticatedOnlyCacheAttribute(Location = System.Web.UI.OutputCacheLocation.Server, Duration = 600, VaryByCustom = "user")]

我认为问题可能是您没有告诉 ASP.NET 您的意思:

VaryByCustom = "user"

也许您这样做了,但是您的 post 中没有包含代码。 在您的 Global.asax.cs 中,您将拥有类似的内容:

public override string GetVaryByCustomString(HttpContext context, string arg) 
{ 
    if (arg.Equals("User", StringComparison.InvariantCultureIgnoreCase)) 
    {
        var user = context.User.Identity.Name; // TODO here you have to pick an unique identifier from the current user identity
        return string.Format("{0}@{1}", userIdentifier.Name, userIdentifier.Container); 
    }

    return base.GetVaryByCustomString(context, arg); 
}

您可以找到关于此的更多信息here and here