nz_21
nz_21

Reputation: 7393

django: how to allow post request only from forms?

I have a simple form:



{% block content %}
<p> Upload invoices </p>
  <form method="post" action="{% url 'upload_thing ' %}" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="file" name="invoice_thing">
    <button type="submit">Upload</button>
  </form>

I have a view


@require_POST
@transaction.atomic
def upload_thing(request): 
      ....

How do I make sure that the no one can hit the post endpoint via curl or postman?

I want the end point to be accessible only by hitting the form button. The only people who can do this are admin users.

How do I accomplish this?

Upvotes: 1

Views: 1096

Answers (2)

Davide Pizzolato
Davide Pizzolato

Reputation: 715

The right way to do this in python is via decorators.

from django.contrib.auth.decorators import login_required, user_passes_test

@user_passes_test(lambda user: user.is_superuser)
def upload_thing(request):

In this way you restrict the method and not the html page. So only logged admin can use upload_thing (from curl, postman, or html form).

Upvotes: 0

ruddra
ruddra

Reputation: 51998

To be honest, you shouldn't prevent curl or wget requests from django application. It can be done from a reverse proxy server, for example in NGINX you can put the following configuration:

if ($http_user_agent ~* (wget|curl) ) {
   return 403;
}

Still, its not a proper protection, User-Agent information can be spoofed. More information can be found in this serverfault answer.

If you want to prevent people accessing this page who aren't admin, then you can simply put a restriction on the view like this:

from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required


@login_required
@require_POST
@transaction.atomic
def upload_thing(request): 
      if not request.user.is_superuser:
        raise PermissionDenied()
      # rest of the code

Upvotes: 1

Related Questions