Hello there! I’d like to ask a few questions regarding restricting views.
Currently, most of my views look a bit like this:
class ExampleView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
fields = ["field_a", "field_b", "field_c"]
model = ExampleModel
permission_required = ["examples.add_examplemodel"]
success_url = reverse_lazy("examples:list")
template_name = "examples/create.html"
I’m checking not only if a user is authenticated, but also if that user has permission to access a given resource.
Out of all my views, I think only 2 or 3 are “public views” (AnonymousUser can access them).
With that said, I’ve been using LoginRequiredMixin and PermissionRequiredMixin because Django provides them out of the box and the documentation is pretty good (Using the Django authentication system | Django documentation | Django). Although I’ve never seen them being used that way (class SomeView(LoginRequiredMixin, PermissionRequiredMixin, ...):
) in the docs or by 3rd party libs, I assume there’s nothing wrong with this approach. Both inherit from AccessMixin, so I guess it’s okay. Please correct me if I’m wrong.
I’d like to upgrade that set up to something more developer friendly by adding a middleware LoginRequiredMiddleware instead of adding LoginRequiredMixin to most of my views.
Can you guys give me some feedback on my current configuration (see below)?
- Does it look good? See any issues?
- Is there a better way to do this?
- LoginRequiredMixin vs. LoginRequiredMiddleware … any reason to prefer one over the other?
- Should I be using
if public_view in path:
instead ofif path.startswith(public_view):
? - Does the middleware order look good?
- Do you know of any reputable libraries that implement something similar?
# settings.py
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.locale.LocaleMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"myapp.middleware.LoginRequiredMiddleware", # <<<==========
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
PUBLIC_VIEWS = [
"app1:login",
"app1:signup",
"app2:landing",
]
# middleware.py
class LoginRequiredMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.public_views = [reverse(view) for view in settings.PUBLIC_VIEWS]
def __call__(self, request):
path = request.get_full_path()
is_public_view = False
for public_view in self.public_views:
if path.startswith(public_view):
is_public_view = True
break
if not is_public_view:
if not request.user.is_authenticated:
return redirect_to_login(path)
if path.startswith(reverse("admin")) and not request.user.is_staff:
raise PermissionDenied("Some message")
return self.get_response(request)
Any feedback is appreciated. Thank you!