Best Way to Make Django's Login_Required the Default

Best way to make Django's login_required the default

Middleware may be your best bet. I've used this piece of code in the past, modified from a snippet found elsewhere:

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required

class RequireLoginMiddleware(object):
"""
Middleware component that wraps the login_required decorator around
matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
settings.py. For example:
------
LOGIN_REQUIRED_URLS = (
r'/topsecret/(.*)$',
)
LOGIN_REQUIRED_URLS_EXCEPTIONS = (
r'/topsecret/login(.*)$',
r'/topsecret/logout(.*)$',
)
------
LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
be a valid regex.

LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
define any exceptions (like login and logout URLs).
"""
def __init__(self):
self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

def process_view(self, request, view_func, view_args, view_kwargs):
# No need to process URLs if user already logged in
if request.user.is_authenticated():
return None

# An exception match should immediately return None
for url in self.exceptions:
if url.match(request.path):
return None

# Requests matching a restricted URL pattern are returned
# wrapped with the login_required decorator
for url in self.required:
if url.match(request.path):
return login_required(view_func)(request, *view_args, **view_kwargs)

# Explicitly return None for all non-matching requests
return None

Then in settings.py, list the base URLs you want to protect:

LOGIN_REQUIRED_URLS = (
r'/private_stuff/(.*)$',
r'/login_required/(.*)$',
)

As long as your site follows URL conventions for the pages requiring authentication, this model will work. If this isn't a one-to-one fit, you may choose to modify the middleware to suit your circumstances more closely.

What I like about this approach - besides removing the necessity of littering the codebase with @login_required decorators - is that if the authentication scheme changes, you have one place to go to make global changes.

Can I change the default `login_required value for all pages in Django-CMS?

I ended up doing it as follows:

In the project's middleware.py I placed the following:

from django.contrib.auth.decorators import login_required

def login_exempt(view):
view.login_exempt = True
return view

class LoginRequiredMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
return self.get_response(request)

def process_view(self, request, view_func, view_args, view_kwargs):
if getattr(view_func, 'login_exempt', False):
return

if 'admin/login' in request.path:
return

if request.user.is_authenticated:
return

return login_required(view_func)(request, *view_args, **view_kwargs)

Which I had to add to my settings.py's MIDDLEWARE list as 'my_project.middleware.LoginRequiredMiddleware'.

And then in my urls.py I had to only decorate those URLs which should not require authentication:

urlpatterns += i18n_patterns(
url(r'^admin/', include(admin.site.urls)),
url(r'^login/$', login_exempt(my_project_views.login_user), name='login'),
url(r'^login$', login_exempt(my_project_views.login_user), name='login'),
url(r'^logout$', login_exempt(my_project_views.logout_user), name='logout'),
...
url(r'^', include('cms.urls')),
)

Django : How can we custom login_required decorator?

Here is my solution :

from django.shortcuts import redirect

def authenticated_user(view_func) :
def wrapper_func(request, *args, **kwargs):

if request.user.is_authenticated and request.session.get('user').get('is_authenticated') :

return view_func(request, *args, **kwargs)

else :

return redirect('login')

return wrapper_func

Suppress ?next=blah behavior in django's login_required decorator

Well, there's two ways that I can think of. First, would be the "correct" way, in the sense that you're not breaking any functionality, only adding new functionality: create your own login_required decorator. The problem though is that Django has really tucked the redirect after login functionality away, and it requires a lot of parts. The login_required decorator is really just a wrapper around the user_passes_test decorator, which in turn calls the redirect_to_login view, and it's that view that adds the next param to the querystring. In your custom decorator, you can roll all or some of this functionality straight into the decorator, but you'll need to reference all three for the necessary code.

The other, and far simpler option, is to create some middleware to remove the querystring if it's set:

from django.conf import settings
from django.http import HttpResponseRedirect

class RemoveNextMiddleware(object):
def process_request(self, request):
if request.path == settings.LOGIN_URL and request.GET.has_key('next'):
return HttpResponseRedirect(settings.LOGIN_URL)

And, then add the import path to that middleware to MIDDLEWARE_CLASSES. Remember that in the request phase, middleware is processed first to last or top-down, in other words. This should come relatively early in the request phase, but you may need to play around a bit with it to see what can and can't come before it.

The only real problem with this method is that it "breaks" the next redirect functionality, and not in a very intuitive way, if a later developer inherits your codebase along with a mandate to allow the redirect, it might be a bit flummoxing.

How to specify the login_required redirect url in django?

LOGIN_URL in your settings

Reference:

  • LOGIN_URL
  • LOGIN_REDIRECT_URL


Related Topics



Leave a reply



Submit