How to turn output caching off for authenticated users in ASP.NET MVC?

后端 未结 3 1367
余生分开走
余生分开走 2020-12-05 01:11

I have an ASP.NET MVC application. I need to cache some pages however only for non-authenticated users.

I\'ve tried to use VaryByCustom=\"user

相关标签:
3条回答
  • 2020-12-05 01:47

    The accepted answer is correct but it doesn't work for caching in this way Partial views. I have combined both variants: GetVaryByCustomString and set Duration to the minimum - for Partial Views and AddValidationCallback method for pages. Actually it is possible to use only the first method but the second one looks not such expensive - it doesn't call OnResultExecuting each time but only registered handler.

    So the custom cache attribute class

    public class CacheAttribute : OutputCacheAttribute
    {   
    
        public CacheAttribute()
        {
          Duration = 300;  /*default cache time*/
        }
    
        private bool _partialView;
    
        /// <summary>
        /// Set true if Partial view is cached
        /// </summary>
        public bool PartialView
        {
          get { return _partialView; }
          set
          {
            _partialView = value;
            if ( _partialView ) {
              VaryByCustom = "Auth";
            }
          }
        }
    
        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;
        }
    }
    

    Override GetVaryByCustomString method in Global.asax.cs

    public override string GetVaryByCustomString(HttpContext context, string custom)
    { 
        if ( custom == "Auth" ) {
          //do not cache when user is authenticated
          if ( context.User.Identity.IsAuthenticated ) {
            return base.GetVaryByCustomString( context, custom );
          }
          return "NotAuth";
        }     
        return base.GetVaryByCustomString( context, custom );
    }
    

    Use it like this:

    [Cache]
    public virtual ActionResult Index()
    {
        return PartialView();
    }
    
    [ChildActionOnly, Cache(PartialView=true)]
    public virtual ActionResult IndexPartial()
    {
        return PartialView();
    }
    

    Updated: I have also added Fujiy's fix here

    0 讨论(0)
  • 2020-12-05 01:51

    So here is what I done:

    public class NonAuthenticatedOnlyCacheAttribute : OutputCacheAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
          var httpContext = filterContext.HttpContext;
    
          if (httpContext.User.Identity.IsAuthenticated)
          {
            // it's crucial not to cache Authenticated content
            Location = OutputCacheLocation.None;
          }
    
          // this smells a little but it works
          httpContext.Response.Cache.AddValidationCallback(IgnoreAuthenticated, null);
    
          base.OnResultExecuting(filterContext);
        }
    
        // 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)
        {
          if (context.User.Identity.IsAuthenticated)            
            validationStatus = HttpValidationStatus.IgnoreThisRequest;          
          else          
            validationStatus = HttpValidationStatus.Valid;          
        }
    }
    

    Many thanks to Craig Stuntz who pointed me to correct direction and whose answer I unwittingly downvoted.

    0 讨论(0)
  • 2020-12-05 01:56

    Attributes in general are cached, then you need to store original Location. If you access the page Logged, it set Location to None, then when you access as anonymous, it still None.

    public class AuthenticatedOnServerCacheAttribute : OutputCacheAttribute
    {
        private OutputCacheLocation? originalLocation;
    
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            var httpContext = filterContext.HttpContext;
    
            if (httpContext.User.Identity.IsAuthenticated)
            {
                originalLocation = originalLocation ?? Location;
                Location = OutputCacheLocation.None;
            }
            else
            {
                Location = originalLocation ?? Location;
            }
    
            base.OnResultExecuting(filterContext);
        }
    }
    
    0 讨论(0)
提交回复
热议问题