Django:我如何将login_required装饰器应用到我的整个站点(静态媒体除外)?

时间:2010-07-09 16:23:22

标签: django django-authentication login-required

example为应用程序级别视图提供了一个片段,但如果我的“urls.py”文件中有很多不同的(和一些非应用程序)条目,包括模板,该怎么办?如何将这个login_required装饰器应用于每个装饰器?

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

10 个答案:

答案 0 :(得分:27)

将其放入项目根目录中的middleware.py文件中(取自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)

然后将projectname.middleware.LoginRequiredMiddleware附加到settings.py中的MIDDLEWARE_CLASSES。

答案 1 :(得分:13)

对于那些稍后来到这里的人,你可能会发现django-stronghold很适合你的用法。您将要公开的任何网址列入白名单,其余的则需要登录。

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

答案 2 :(得分:8)

这是一个稍短的中间件。

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)

您必须在每个不需要登录的视图中将“login_required”设置为False即可查看:

功能的视图:

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

基于类的视图:

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

#or

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

这意味着你必须对登录视图做一些事情,但我总是最终编写自己的auth-backend。

答案 3 :(得分:3)

这是Django 1.10 +的经典LoginRequiredMiddleware

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)

值得注意的差异:

  • path.to.LoginRequiredMiddleware应包含在settings.py中的MIDDLEWARE而不是MIDDLEWARE_CLASSES
  • is_authenticated是bool而不是方法。
  • 有关详情,请参阅docs(虽然有些部分不是很清楚)。

答案 4 :(得分:2)

使用中间件。

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

我假设这在1.2

中没有发生太大的变化

中间件允许您创建一个类,该类具有将在您定义的不同时间/条件下处理每个请求的方法。

例如,process_request(request)会在您的视图之前触发,此时您可以强制进行身份验证和授权。

答案 5 :(得分:1)

先前的一些答案要么已经过时(Django的较旧版本),要么引入了不良的编程习惯(硬编码URL,不使用路由)。这是我认为更干燥且可持续/可维护的观点(改编自Mehmet's answer above)。

要在此处强调改进之处,这取决于为URL提供路由名(比使用更改且带有斜杠/前导斜杠的硬编码URL / URI更可靠)。

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))

settings.py文件中,您可以定义以下内容:

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

答案 6 :(得分:0)

除了 meder omuraliev ,如果您想要这样的免费网址(使用正则表达式),请回答:

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

将它添加到EXEMPT_URLS列表中,如下所示:

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

r&#39; ..&#39; 在必要字符串的开头。

答案 7 :(得分:0)

Django登录所需中间件

将此代码放在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)

并且,在settings.py中:

LOGIN_URL = '/app_name/login'

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

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

像这样: 'app_name.middleware.LoginRequiredMiddleware'

答案 8 :(得分:0)

如果您有很多看法而又不想碰任何人,则可以使用中间件解决此问题。请尝试以下代码:


import traceback
from django.contrib.auth.decorators import login_required


class RejectAnonymousUsersMiddleware(object):

    def process_view(self, request, view_func, view_args, view_kwargs):
        current_route_name = resolve(request.path_info).url_name

        if current_route_name in settings.AUTH_EXEMPT_ROUTES:
            return

        if  request.user.is_authenticated:
            return

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

注意事项:

  • 您必须将此中间件添加到中间件部分的最底部 settings.py
  • 您应该将此变量放在settings.py中
    • AUTH_EXEMPT_ROUTES =('注册','登录','忘记密码')

答案 9 :(得分:-1)

以下是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

此示例免除管理员登录表单以避免重定向循环,并将该表单用作登录URL。