开发者

Can login_required by applied to an entire app?

Is there a way I can apply the login_required decorator to an entire app? When I say "app" I mean it in the django sense, which is to say a set of urls and vie开发者_如何转开发ws, not an entire project.


Yes, you should use middleware.

Try to look through solutions which have some differences:

  • http://www.djangosnippets.org/snippets/1179/ - with list of exceptions.
  • http://www.djangosnippets.org/snippets/1158/ - with list of exceptions.
  • http://www.djangosnippets.org/snippets/966/ - conversely with list of login required urls.
  • http://www.djangosnippets.org/snippets/136/ - simplest.


I think you are looking for this snippet, containing login-required middleware.


This is an old question. But here goes:

Django Decorator Include

This is a substitute of include in URLConf. Pefect for applying login_required to an entire app.


As of Django 3+, you can set login_require() to an entire app by applying a middleware. Do like followings:

Step 1: Create a new file anything.py in your yourapp directory and write the following:

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

//for registering a class as middleware you at least __init__() and __call__()
//for this case we additionally need process_view() which will be automatically called by Django before rendering a view/template

class ClassName(object):
    
    //need for one time initialization, here response is a function which will be called to get response from view/template
    def __init__(self, response):
        self.get_response = response
        self.required = tuple(re.compile(url) for url in settings.AUTH_URLS)
        self.exceptions = tuple(re.compile(url)for url in settings.NO_AUTH_URLS)

    def __call__(self, request):
        //any code written here will be called before requesting response
        response = self.get_response(request)
        //any code written here will be called after response
        return response

    //this is called before requesting response
    def process_view(self, request, view_func, view_args, view_kwargs):
        //if authenticated return no exception
        if request.user.is_authenticated:
            return None
        //return login_required()
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)
        //default case, no exception
        return None

Step 2: Add this anything.py to Middleware[] in project/settings.py like followings

MIDDLEWARE = [
    // your previous middleware
    'yourapp.anything.ClassName',
]

Step 3: Also add the following snippet into project/settings.py

AUTH_URLS = (
    //disallowing app url, use the url/path that you added on mysite/urls.py (not myapp/urls.py) to include as your app urls
    r'/your_app_url(.*)$',
)


I clicked all the links in the anwsers, but they were all based on some kind of regular expressions. On Django 3+ you can do the following to restrict for a specific app:

  • Declare app_name="myapp" in your app's urls.py (https://docs.djangoproject.com/en/3.2/intro/tutorial03/#namespacing-url-names) (now all these urls should be called with there namespace "myapp:urlname")
  • Create a middleware.py file in your app with this:
from django.contrib.auth.views import redirect_to_login
from django.core.exceptions import ImproperlyConfigured

from django.urls import resolve


class LoginRequiredAccess:
   """All urls starting with the given prefix require the user to be logged in"""

   APP_NAME = 'myapp'

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

   def __call__(self, request):
       if not hasattr(request, 'user'):
           raise ImproperlyConfigured(
               "Requires the django's authentication middleware"
               " to be installed.")

       user = request.user
       if resolve(request.path).app_name == self.APP_NAME:  # match app_name defined in myapp.urls.py
           if not user.is_authenticated:
               path = request.get_full_path()
               return redirect_to_login(path)

       return self.get_response(request)

  • Put "myapp.middleware.LoginRequiredAccess" in your MIDDLEWARE constant from settings.py
  • Then in your main project urls.py
urlpatterns = [
    path('foobar', include('otherapp.urls')),  # this will not be redirected
    path('whatever', include('myapp.urls')),  # all these urls will be redirected to login
]

On of the avantage of this method is it can still works with a root url path, e.g path('', include('myapp.urls')), while the others will do an infinite redirect loop.


I'm wondering if there is any solution to make it works like this:

/app/app.py
class AppConfig(AppConfig):
    login_required = True

/project/urls.py
urlpatterns = [
    url(r'app/', include('app.urls', namespace='app'))
]

/common/middleare.py
def LogMiddleware(get_response):
    def middleware(request):
        # solution 1
        app = get_app(request)
        if app.login_required is True and request.is_authenticated is Fasle:
            return HttpResponseRedirect(redirect_url)
        # solution 2
        url_space = get_url_space(request.get_raw_uri())
        if url_space.namespace in ['app', 'admin', 'staff', 'manage'] and \
                request.is_authenticated is False:
            return HttpResponseRedirect(redirect_url)

I will check if there is any methoded to get the app or url name of a request. I think it looks prettier.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜