views:

125

answers:

2

I'm building an ASP.NET MVC 2 site where I'm using the OutputCache parameter heavily. However, I have a concern: using such caching may interfere with authentication.

On all of my pages, I display whether the user is logged in or not. Furthermore, in some of my Views, I do filtering based on user role to determine whether or not to display some page content (for example, the Edit link on one of my pages is only shown to users in the roles of Moderator or Administrator).

Will using OutputCache interfere with this dynamic changing of my Views? If so, how can I resolve this problem without eliminating caching?

+1  A: 

I believe what you need is ASP.NET donunt caching. See here for a good explaination. I wouldn't be suprised if SO uses something like this for the top bar area.

madcapnmckay
That link says that it's not recommended to do that in MVC2...
Maxim Zaslavsky
+2  A: 

The [OutputCache] and [Authorize] attributes play well with one another. The AuthorizeAttribute.OnAuthorization() method sets a hook into the output caching system that forces the authorization filter to re-run before the page is served from the cache. If the authorization filter logic fails, it will be treated as a cache miss. If the authorization logic succeeds, the page will be served from the cache. So if you have [Authorize(Roles = "Moderator, Administrator")] and [OutputCache] on an action, the page will not be served from the cache unless the current user is in the Moderator or Administrator roles.

Note that this does not vary by user or role; it's literally re-running the original check. Imagine that User A (who is a Moderator) comes in and causes the page to be cached. Now User B (who is an Administrator) comes in and hits the cached page. The [Authorize] check will succeed since both Administrator and Moderator are allowed, and the response served to User B will contain the exact same contents as the response that was served to User A.

Note that response substitution does not work in MVC 2. If you're serving potentially sensitive data, the best bet here is not to cache it. If you absolutely need to cache, you can mimic something similar to response substitution by using an AJAX callback to dynamically fill in the missing data.

Levi
What if I have a method that doesn't require authorization but adds an Edit link inside the View if the user is a moderator? In this case, I'm trying to accomplish something that resembles how the link, flag, edit, and other buttons under a question or answer here work - doesn't SO use OutputCache, too? Thanks for your answer!
Maxim Zaslavsky
I just stumbled across http://blog.stevensanderson.com/2008/10/15/partial-output-caching-in-aspnet-mvc/ (about an old problem that was later fixed), which gave me an idea - if OutputCache is so bad with this, is it possible to **build a custom caching attribute/filter** that creates different copies based on whether the user is logged-in and what roles the user is in - or better yet, what the username is, as I'm going to write the name of the user at the top of the page - **is that possible**?
Maxim Zaslavsky
It's generally a bad idea to cache per-user, as your cache is going to be flooded with entries. If donut caching is important to your scenario, you could also use a response filter. At the beginning of the request, install a filter that understands some [!! SUBSTITUTION DATA !!] pattern, have your WriteSubstitute() write this pattern to the response stream, then at the end of the request your filter would call into the actual Response.WriteSubstitution() method.
Levi
To answer your question re: varying by pretty much anything (including username), see http://aspadvice.com/blogs/ssmith/archive/2007/10/29/VaryByCustom-Caching-By-User.aspx and http://msdn.microsoft.com/en-us/library/system.web.mvc.outputcacheattribute.varybycustom.aspx. Remember though that this is not recommended.
Levi
I ended up completely cutting caching for authenticated users on the advice of Jeff Atwood at http://meta.stackoverflow.com/questions/60403/how-does-stack-overflow-do-caching/60406#60406
Maxim Zaslavsky