How to redirect users trying to access Private Page to custom page instead of login page?

Viewed 355

Need Help, I was able to set up login system on Wagtail website using django-allauth. I have two groups Free and Premium. By default when user registers they are assigned "Free" group role. When they log in they have access to Free articles. When they try to access Private articles meant for "Premium" group they are redirected to wagtail login page. Is there any way to redirect logged in free group users to custom page instead of login page?

2 Answers

I had a similar problem where the user got redirected to the login page even though he was already logged in but just failed the permission check. I solved this in the following way.

I override the wagtail check_view_restrictions in my own wagtail_hooks.py file.

I simply added another elif statement to check if the user is authenticated and the page in question has group permissions and then redirect to my dashboard page where I handle the popup modal logic in my DashboardPage's serve method.

...

elif request.user.is_authenticated and restriction.restriction_type == PageViewRestriction.GROUPS:
          return redirect(f'/dashboard/?next={request.get_full_path()}')
...

full function:

from django.conf import settings
from django.urls import reverse
from django.contrib.auth.views import redirect_to_login
from django.shortcuts import redirect
from wagtail.core.models import PageViewRestriction

hooks.register('before_serve_page')
def check_view_restrictions(page, request, serve_args, serve_kwargs):
    """
    Overriding wagtail check_view_restrictions to redirect a user to the dashboard
    when they are logged in and the page has groups restriction_type.
    The dashboard serve view is handling the permission denied modal
    """
    for restriction in page.get_view_restrictions():
      if not restriction.accept_request(request):
        if restriction.restriction_type == PageViewRestriction.PASSWORD:
          from wagtail.core.forms import PasswordViewRestrictionForm
          form = PasswordViewRestrictionForm(instance=restriction,
                                              initial={'return_url': request.get_full_path()})
          action_url = reverse('wagtailcore_authenticate_with_password', args=[
                                restriction.id, page.id])
          return page.serve_password_required_response(request, form, action_url)

        elif request.user.is_authenticated and restriction.restriction_type == PageViewRestriction.GROUPS:
          return redirect(f'/dashboard/?next={request.get_full_path()}')
        elif restriction.restriction_type == PageViewRestriction.LOGIN:
          return require_wagtail_login(next=request.get_full_path())

I use the next parameter in the URL in the serve method to check if the user has the correct permissions to view that page. You can add your own required logic here

You can use several things to check if the user has a certain permission or belongs to a certain group.

For example, you can use the decorator @permission_required

from django.contrib.auth.decorators import permission_required

@permission_required('polls.add_choice', login_url='/loginpage/')
def my_view(request):
    ...

That will redirect all users to the login_url if they try to access the view without any permission.

You can also do the same to a custom requirement created by you:

from django.contrib.auth.decorators import user_passes_test

def email_check(user):
    return user.email.endswith('@example.com')

@user_passes_test(email_check)
def my_view(request):
    ...

That will allow users to access that view if the return statement in the test is truthy. However, these methods are for the entire view. If you want to render specific content you can also have these "checks":

def my_view(request):
    if user.has_perm('myapp.change_blogpost'):
        # ... 
    if not request.user.email.endswith('@example.com'):
        # ...
Related