aqpcserver
aqpcserver

Reputation: 66

Django prevent direct url access

Lets say I have

.decs

def unwelcome_user(unwelcome_roles=[]):
        def decorator(view_func):
            def wrapper_func(request, *args, **kwargs):
                if request.user.is_authenticated:
                    for group in request.user.groups.all():
                        if group.name in unwelcome_roles:
                            return redirect('main:unwelcome-user-type', 
                                             user_type=group.name)
                        else:
                            return view_func(request, *args, **kwargs)
                else:
                    return view_func(request, *args, **kwargs)
            return wrapper_func
        return decorator

.urls

urlpatterns = [
    path('error-unwelcome/<str:user_type>', views.unwelcome_user, name='success')
]

.views

@unwelcome_user(unwelcome_roles=['xyz'])
def success(request) 
    return render(request, 'success_page.html', {})

def unwelcome_user(request, user_type):
return render(request, 'errors/unwelcome_user.html', {})

I can access the unwelcome_user view directly by typing something like mysite.com/error-unwelcome/xyz in the browser even without going through the subsequent process that should result in showing that page. How do I prevent that?

Upvotes: 0

Views: 2375

Answers (4)

aqpcserver
aqpcserver

Reputation: 66

I'm still new to Django so I couldn't try out the cookie/sessions answers given (I still have to learn sessions). In the meantime, here's what I'm using:

def get_referer(request):
    referer = request.META.get('HTTP_REFERER')
    if not referer:
        return None
    return referer

then in any view

def my_view(request):
    if not get_referer(request):
        raise Http404
    return render(request, 'sample.html', {})

Here I'm assuming that if there's no referer, then it means the person typed in the URL into the browser.

Upvotes: 2

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21812

You can try using sessions [Django docs]. If you are redirecting a user to the page, before redirecting just add a variable to the session indicating that they can access the view.

So just before the redirect:

request.session['is_unwelcome'] = True
return redirect('main:unwelcome-user-type', user_type=group.name)

In the view you would simply check whether the variable is present in the session:

def unwelcome_user(request, user_type):
    if 'is_unwelcome' not in request.session:
        # Redirect or raise Http 404?
        # return redirect('somewhere')
        # raise Http404()
    del request.session['is_unwelcome']
    return render(request, 'errors/unwelcome_user.html', {})

Upvotes: 0

Sumithran
Sumithran

Reputation: 6565

Give this a try

The process_page will only render success.html if your_subsequent_process() returns a True, otherwise, the process.html will be rendered.

def proces_page(request):
    """Your Process View"""
    
    if your_subsequent_process():
        return render(request, 'success.html', {})

    return render(request, 'proces.html', {})

Upvotes: 0

arkaeologic
arkaeologic

Reputation: 85

If the page is part of a chain of pages for the user to navigate, you will need to pass some state when moving from one page to the next. You can either use a cookie and check the value of the cookie in the view, or pass a GET query parameter:

def success(request):
  token = request.GET.get('token', None)

  if token is None or not Token.objects.filter(value=token).exists():
    return redirect(...) # previous step or beginning

  return render(...) # page

Previous pages should create this token. Then pass it in the URL:

/success/?token=<token>

Upvotes: 0

Related Questions