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

med*_*iev 23 django django-authentication login-required

示例提供了应用程序级视图的代码段,但如果我的"urls.py"文件中包含许多不同(和某些非应用程序)条目(包括模板),该怎么办?如何将这个login_required装饰器应用于每个装饰器?

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

med*_*iev 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)
Run Code Online (Sandbox Code Playgroud)

然后projectname.middleware.LoginRequiredMiddleware在settings.py中附加到我的MIDDLEWARE_CLASSES.

  • 我认为这个解决方案非常棒.我[调整它](https://gist.github.com/TomasTomecek/5056424)有点支持`redirect`并通过`reverse`获取登录URL. (6认同)

Jus*_*hms 13

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

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

  • 这个解决方案看起来比安装和维护自己的中间件要优雅得多。效果非常好。 (2认同)

kal*_*sin 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)
Run Code Online (Sandbox Code Playgroud)

您必须在每个不需要登录的视图上将"login_required"设置为False以查看:

函数的观点:

def someview(request, *args, **kwargs):
    # body of view
someview.login_required = False
Run Code Online (Sandbox Code Playgroud)

基于类的视图:

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

#or

class SomeView(View):
    # body of view
someview = SomeView.as_view()
someview.login_required = False
Run Code Online (Sandbox Code Playgroud)

这意味着你必须对登录视图做一些事情,但无论如何我总是写自己的auth-backend.


dKe*_*Ken 8

之前的一些答案要么已经过时(Django 的旧版本),要么引入了糟糕的编程实践(硬编码 URL,不使用路由)。这是我的看法,它更加干燥和可持续/可维护(改编自上面 Mehmet 的回答)。

为了突出这里的改进,这依赖于提供 URL 路由名称(这比使用硬编码的 URL/URI 更可靠,这些 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))
Run Code Online (Sandbox Code Playgroud)

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

AUTH_EXEMPT_ROUTES = ('register', 'login', 'forgot-password')
AUTH_LOGIN_ROUTE = 'register'
Run Code Online (Sandbox Code Playgroud)