Set all pages to require login, globally?

落花浮王杯 提交于 2019-12-18 11:41:17

问题


I want to redirect access of unauthenticated users to the login page, after which the logged-in user should be redirected to the originally requested page.

According to documentation, this is easily achieved using the @user_passes_test decorator. But it seems I'd have to decorate every view, which is crazy, there are too many and it's error-prone.

What is a good way to turn on this functionality globally (except for a small fixed set of views, such as login)? That is, default everything to logged-in-only + handle anonymous viewing explicitly, where needed.


回答1:


have a look at middleware. these are functions run at various points in the request cycle, e.g. before each view is called.

since you may want to exclude certain views from this, i'd look at e.g. how the csrf middleware works, together with the csrf_exempt decorator.

see [SOURCE]/django/views/decorators/csrf.py and [SOURCE]/django/middleware/csrf.py




回答2:


The way I solved this, was to have mixin class, with the decorator (or whatever code you need). Although you have to remember to call the super(Class, self).get(...) function, so I guess it's not so different after all.

On the other hand, having a set of mixins that does different things I found was quite good at getting a very simple view to do a lot without much code.

Edit

This is how I did in my last project:

class BaseAuthMixin(object):
    def auth_check(self, user):
        return True

    def dispatch(self, request, *args, **kwargs):
        if not self.auth_check(request.user):
            from django.http import HttpResponseRedirect
            from django.contrib.auth import logout

            is_web = False
            is_live = False

            if hasattr(self, 'get_url_name'):
                from django.core.urlresolvers import reverse
                from django.core.urlresolvers import NoReverseMatch

                try:
                    next = reverse(self.get_url_name(), kwargs=kwargs)
                except NoReverseMatch:
                    next = ''
                else:
                    next= '?next=' + next

            logout(request)

            redirect_url = settings.LOGIN_URL
            redirect_url += next

            return HttpResponseRedirect(redirect_url)
        else:
            return super(BaseAuthMixin, self).dispatch(request, *args, **kwargs)

class LoginRequiredMixin(BaseAuthMixin):
    """
    Check if the view needs the user to be logged in.
    """
    def auth_check(self, user):
        if not super(LoginRequiredMixin, self).auth_check(user):
            return False
        else:
            if hasattr(self, 'login_required'):
                if self.login_required and not user.is_authenticated():
                    return False
        return True

class MyDefaultMixin(LoginRequiredMixin):
    """
    Mixin that inherits from all common view mixins.
    """
    pass

The above is then used by the view-classes (I used Django 1.3 with class-based views):

from django.views.generic import TemplateView

class SomeViewClass(TemplateView, MyDefaultMixin):
    # Used by 'LoginRequiredMixin' to check if a user has to be logged in
    login_required = True

    # Template for the Django TemplateView
    template_name = "some_view_template.html"

You need a view to handle the login (with URL in settings.LOGIN_URL), containing a form with a hidden field called next. This field has to be set by a context variable to the page to go to after successful login.

If all views inherit from the base mixin (MyDefaultMixin in my code above), it will automatically check that the user is logged in iv the view contain an attribute called login_required and that is set to True.

There might be better ways to do this, but this is what I did and it worked very well.




回答3:


from django.shortcuts import redirect
from django.conf import settings


class LoginRequiredMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.login_url = settings.LOGIN_URL
        self.open_urls = [self.login_url] + \
                         getattr(settings, 'OPEN_URLS', [])

    def __call__(self, request):
        if not request.user.is_authenticated \
        and not request.path_info in self.open_urls:
            return redirect(self.login_url+'?next='+request.path)

        return self.get_response(request)


来源:https://stackoverflow.com/questions/8377086/set-all-pages-to-require-login-globally

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