简体   繁体   中英

Django rest-api: Postman can't see CSRF token

I'm using django 1.11.6 and python 3.5 on an ubuntu server.

I have an api for user registration.

This is my curl command:

curl -i -H 'Accept: application/json; indent=4'  -X POST  https://mydomain/users/:register/ -d "id=222111&firstname=andy&yearofbirth=2007&lastname=Chris&othernames=" 

When I use it in cygwin I get this response which is the desired:

HTTP/1.1 200 OK
Date: Thu, 26 Oct 2017 06:41:00 GMT
Server: Apache/2.4.18 (Ubuntu)
Allow: POST, OPTIONS
Vary: Accept,Cookie
Content-Length: 188
X-CSRFToken: acY2oPGkkqkzBe9itBq56oFeTFAllqv2bS39c7TpPN9LlGh90E1FxsI0YXLlu1Vu
X-Frame-Options: SAMEORIGIN
Set-Cookie:  csrftoken=QfxnUGTmrRi1MThcn8Qau5ytnt2NR8tdRVCuIY6rWe7dwlp3UbrKV9BfsLdN0JTF; expires=Thu, 25-Oct-2018 06:41:01 GMT; Max-Age=31449600; Path=/
Content-Type: application/json

{
    "isnew": "true",
    "user": {
        "othernames": "",
        "id": "222111",
        "firstname": "Andy",
        "yearofbirth": 2007,
        "lastnames": "Chris"
    }
}

As I can see, I have X-CSRFToken header and `csrftoken' cookie.

When I try to run the same curl command from postman I get:

Forbidden (403)
CSRF verification failed. Request aborted.
You are seeing this message because this HTTPS site requires a 'Referer header' to be sent by your Web browser, but none was sent. This header is required for security reasons, to ensure that your browser is not being hijacked by third parties.
If you have configured your browser to disable 'Referer' headers, please re-enable them, at least for this site, or for HTTPS connections, or for 'same-origin' requests.

My function in views.py is:

class ApiUserRegister(APIView):
    permission_classes = ()
    serializer_class = RegisterUserSerializer

    def post(self, request):
        serializer = RegisterUserSerializer(data=request.data)
        # Check format and unique constraint
        serializer.is_valid(raise_exception=True)
        data = serializer.data

        if User.objects.filter(id=data['id']).exists():
            user = User.objects.get(id=data['id'])
            is_new = "false"
            resp_status = status.HTTP_200_OK
        else:
            user = User.objects.create(id=data['id'],
                                       firstname=data['firstname'],
                                       yearofbirth=data['yearofbirth'],
                                       lastname=data['lastname'],
                                       othernames=data['othernames'])
            user.save()
            is_new = "true"
            resp_status = status.HTTP_201_CREATED
        resp = {"user": serializer.get_serialized(user),
                "isnew": is_new} #csrfmiddlewaretoken: csrf_token
        return Response( resp, status=resp_status, headers = {"X-CSRFToken":get_token(request)})

You can create an additional view to generate CSRF tokens which you can first gather by a GET request.

Example :

# views.py

from django.middleware.csrf import get_token

class CSRFGeneratorView(APIView):
    def get(self, request):
        csrf_token = get_token(request)
        return Response(csrf_token)

# urls.py

urlpatterns += [url(r'generate_csrf/$', views.CSRFGeneratorView.as_view())]

You can then call this view first to gain the CSRF token to use in further requests.

EDIT: After getting the token, you will add this to form data.

Example :

curl -X POST -d "csrfmiddlewaretoken=<token_value>" <url>

Ref: How CSRF works

Good to know

Django sets csrftoken cookie on login. After logging in, we can see the csrf token from cookies in the Postman. (see image) CSRFtoken from cookies


First approach ...


We can grab this token and set it in headers manually. But this token has to be manually changed when it expires. This process becomes tedious to do it on an expiration basis.


Better way ...


Instead, we can use Postman scripting feature to extract the token from the cookie and set it to an environment variable. In Test section of the postman, add these lines.

var xsrfCookie = postman.getResponseCookie("csrftoken"); postman.setEnvironmentVariable('csrftoken', xsrfCookie.value);

This extracts csrf token and sets it to an environment variable called csrftoken in the current environment. Now in our requests, we can use this variable to set the header.(see image) Set {{csrftoken}} in your header

When the token expires, we just need to log in again and csrf token gets updated automatically.

Thanks to @chillaranand from hackernoon.com for original post

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM