Django: How can I apply the login_required decorator to my entire site (excluding static media)?

六月ゝ 毕业季﹏ 提交于 2019-12-18 10:42:51

问题


The example provides a snippet for an application level view, but what if I have lots of different (and some non-application) entries in my "urls.py" file, including templates? How can I apply this login_required decorator to each of them?

(r'^foo/(?P<slug>[-\w]+)/$', 'bugs.views.bug_detail'),
(r'^$', 'django.views.generic.simple.direct_to_template', {'template':'homepage.html'}),

回答1:


Dropped this into a middleware.py file in my project root (taken from http://onecreativeblog.com/post/59051248/django-login-required-middleware)

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

EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
    EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]

class LoginRequiredMiddleware:
    """
    Middleware that requires a user to be authenticated to view any page other
    than LOGIN_URL. Exemptions to this requirement can optionally be specified
    in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
    you can copy from your urls.py).

    Requires authentication middleware and template context processors to be
    loaded. You'll get an error if they aren't.
    """
    def process_request(self, request):
        assert hasattr(request, 'user'), "The Login Required middleware\
 requires authentication middleware to be installed. Edit your\
 MIDDLEWARE_CLASSES setting to insert\
 'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\
 work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\
 'django.core.context_processors.auth'."
        if not request.user.is_authenticated():
            path = request.path_info.lstrip('/')
            if not any(m.match(path) for m in EXEMPT_URLS):
                return HttpResponseRedirect(settings.LOGIN_URL)

Then appended projectname.middleware.LoginRequiredMiddleware to my MIDDLEWARE_CLASSES in settings.py.




回答2:


For those who have come by later to this, you might find that django-stronghold fits your usecase well. You whitelist any urls you want to be public, the rest are login required.

https://github.com/mgrouchy/django-stronghold




回答3:


Here's a slightly shorter middleware.

from django.contrib.auth.decorators import login_required

class LoginRequiredMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if not getattr(view_func, 'login_required', True):
            return None
        return login_required(view_func)(request, *view_args, **view_kwargs)

You'll have to set "login_required" to False on each view you don't need to be logged in to see:

Function-views:

def someview(request, *args, **kwargs):
    # body of view
someview.login_required = False

Class-based views:

class SomeView(View):
    login_required = False
    # body of view

#or

class SomeView(View):
    # body of view
someview = SomeView.as_view()
someview.login_required = False

This means you'll have to do something about the login-views, but I always end up writing my own auth-backend anyway.




回答4:


Here is the classical LoginRequiredMiddleware for Django 1.10+:

from django.utils.deprecation import MiddlewareMixin

class LoginRequiredMiddleware(MiddlewareMixin):
    """
    Middleware that requires a user to be authenticated to view any page other
    than LOGIN_URL. Exemptions to this requirement can optionally be specified
    in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
    you can copy from your urls.py).
    """
    def process_request(self, request):
        assert hasattr(request, 'user'), """
        The Login Required middleware needs to be after AuthenticationMiddleware.
        Also make sure to include the template context_processor:
        'django.contrib.auth.context_processors.auth'."""
        if not request.user.is_authenticated:
            path = request.path_info.lstrip('/')
            if not any(m.match(path) for m in EXEMPT_URLS):
                return HttpResponseRedirect(settings.LOGIN_URL)

Noteworthy differences:

  • path.to.LoginRequiredMiddleware should be included in MIDDLEWARE not MIDDLEWARE_CLASSES in settings.py.
  • is_authenticated is a bool not a method.
  • see the docs for more info (although some parts are not very clear).



回答5:


Use middleware.

http://www.djangobook.com/en/2.0/chapter17/ and http://docs.djangoproject.com/en/1.2/topics/http/middleware/#topics-http-middleware

I'm assuming this didn't change a whole lot in 1.2

Middleware allows you to create a class with methods who will process every request at various times/conditions, as you define.

for example process_request(request) would fire before your view, and you can force authentication and authorization at this point.




回答6:


Some of the previous answers are either outdated (older version of Django), or introduce poor programming practices (hardcoding URLs, not using routes). Here's my take that is more DRY and sustainable/maintainable (adapted from Mehmet's answer above).

To highlight the improvements here, this relies on giving URLs route names (which are much more reliable than using hard-coded URLs/URIs that change and have trailing/leading slashes).

from django.utils.deprecation import MiddlewareMixin
from django.urls import resolve, reverse
from django.http import HttpResponseRedirect
from my_project import settings

class LoginRequiredMiddleware(MiddlewareMixin):
    """
    Middleware that requires a user to be authenticated to view any page other
    than LOGIN_URL. Exemptions to this requirement can optionally be specified
    in settings by setting a tuple of routes to ignore
    """
    def process_request(self, request):
        assert hasattr(request, 'user'), """
        The Login Required middleware needs to be after AuthenticationMiddleware.
        Also make sure to include the template context_processor:
        'django.contrib.auth.context_processors.auth'."""

        if not request.user.is_authenticated:
            current_route_name = resolve(request.path_info).url_name

            if not current_route_name in settings.AUTH_EXEMPT_ROUTES:
                return HttpResponseRedirect(reverse(settings.AUTH_LOGIN_ROUTE))

And in the settings.py file, you can define the following:

AUTH_EXEMPT_ROUTES = ('register', 'login', 'forgot-password')
AUTH_LOGIN_ROUTE = 'register'



回答7:


In addition to meder omuraliev answer if you want exempt url like this (with regexp):

url(r'^my/url/(?P<pk>[0-9]+)/$', views.my_view, name='my_url')

add it to EXEMPT_URLS list like this:

LOGIN_EXEMPT_URLS = [r'^my/url/([0-9]+)/$']

r'..' in the beginning of the string necessary.




回答8:


Django Login Required Middleware

Put this code in middleware.py :

from django.http import HttpResponseRedirect
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
from re import compile

EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
    EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]

class LoginRequiredMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'user')
        if not request.user.is_authenticated:
            path = request.path_info.lstrip('/')
            if not any(m.match(path) for m in EXEMPT_URLS):
                return HttpResponseRedirect(settings.LOGIN_URL)

And, in settings.py :

LOGIN_URL = '/app_name/login'

LOGIN_EXEMPT_URLS=(
    r'/app_name/login/',
)

MIDDLEWARE_CLASSES = (
    # ...
    'python.path.to.LoginRequiredMiddleware',
)

Like this : 'app_name.middleware.LoginRequiredMiddleware'




回答9:


Here's an example for new-style middleware in Django 1.10+:

from django.contrib.auth.decorators import login_required
from django.urls import reverse

def login_required_middleware(get_response):
    """
        Require user to be logged in for all views. 
    """
    exceptions = {'/admin/login/'}
    def middleware(request):
        if request.path in exceptions:
            return get_response(request)
        return login_required(get_response, login_url=reverse('admin:login'))(request)
    return middleware

This example exempts the admin login form to avoid redirect loop, and uses that form as the login url.



来源:https://stackoverflow.com/questions/3214589/django-how-can-i-apply-the-login-required-decorator-to-my-entire-site-excludin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!