import re import django.conf as conf import django.contrib.auth.decorators as ad class UserPassesTestMiddleware(object): """ Originally adapted from mattgrayson's snippet at http://www.djangosnippets.org/snippets/1219/. Middleware component that wraps the user_passes_test decorator around views for matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and define USER_PASSES_TEST_URLS in your settings.py. The following example limits access to anything under "/topsecret/" to authenticated users: USER_PASSES_TEST_URLS = ( (r'^/topsecret/', lambda u: u.is_authenticated), ) The following example locks down a typical site, giving access to staff only: USER_PASSES_TEST_URLS = ( (r'^/$', None), (r'^/login/$', None), (r'^/logout/$', None), (r'^/media/', None), (r'^/passwordreset/', None), (r'', lambda u: u.is_staff), ) Note that patterns with a test of "None" pass the matching view through unwrapped. Also, this example works because the order of USER_PASSES_TEST_URLS matters. The first matching pattern is the only one applied. Views already wrapped in an auth decorator are untouched, so permissions can still be controlled on a view-by-view basis. """ def __init__(self): self.urls = [(re.compile(pattern), test) for pattern, test in conf.settings.USER_PASSES_TEST_URLS] def process_view(self, request, view_func, view_args, view_kwargs): # don't wrap if function is already wrapped if getattr(view_func, 'decorator', None): return for regex, test in self.urls: if regex.search(request.path): if test: # return view wrapped in test return ad.user_passes_test(test)(view_func)(request, *view_args, **view_kwargs) else: # no test, don't wrap return