Created
July 2, 2012 10:24
-
-
Save tomds/3032515 to your computer and use it in GitHub Desktop.
Django site-wide login required middleware including AJAX support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Based on http://djangosnippets.org/snippets/1158/ | |
import json | |
import re | |
from django.conf import settings | |
from django.http import HttpResponse, HttpResponseRedirect | |
class EnforceLoginMiddleware(object): | |
""" | |
Middlware class which requires the user to be authenticated for all urls except | |
those defined in PUBLIC_URLS in settings.py. PUBLIC_URLS should be a tuple of regular | |
expresssions for the urls you want anonymous users to have access to. If PUBLIC_URLS | |
is not defined, it falls back to LOGIN_URL or failing that '/accounts/login/'. | |
Requests for urls not matching PUBLIC_URLS get redirected to LOGIN_URL with next set | |
to original path of the unauthenticted request. | |
""" | |
def __init__(self): | |
self.login_url = getattr(settings, 'LOGIN_URL', '/accounts/login/' ) | |
if hasattr(settings,'PUBLIC_URLS'): | |
public_urls = [re.compile(url) for url in settings.PUBLIC_URLS] | |
else: | |
public_urls = [(re.compile("^%s$" % ( self.login_url[1:] )))] | |
self.public_urls = tuple(public_urls) | |
def process_request(self, request): | |
""" | |
Redirect anonymous users to login_url from non public urls | |
""" | |
redirect_to_login = False | |
try: | |
if request.user.is_anonymous(): | |
for url in self.public_urls: | |
if url.match(request.path): | |
return None | |
redirect_to_login = True | |
except AttributeError: | |
redirect_to_login = True | |
if redirect_to_login: | |
# Return a 401 for AJAX requests so it's easy to tell from JS that login is required | |
if request.is_ajax() or \ | |
'application/json' in request.META.get('HTTP_ACCEPT', '') or \ | |
request.POST.get('httpAccept') == 'json': | |
return HttpResponse(json.dumps({'loginRedirect': True}), status=401) | |
return HttpResponseRedirect("%s?next=%s" % (self.login_url, request.path)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PUBLIC_URLS = ( | |
r'^/login/', | |
r'^/logout/', | |
r'^/register/', | |
r'^/forgotten/', | |
r'^/reset/', | |
r'^%s' % STATIC_URL, | |
r'^/jsi18n/' | |
) |
Thanks for sharing, this is very useful.
One suggestion - we should really return 404 if the page doesn't exist:
from django.core.urlresolvers import resolve, Resolver404
...
try:
resolve(request.path)
redirect_to_login = True
except Resolver404:
'not found'
...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you want the django core tests to still pass, you'll need a separate settings file that removes the middleware and then use the --settings parameter when running tests.