Django Rest framework replaces my current authenticated user with AnonymousUser whenever I call it through ajax?

I am trying to add some interactive things to the Django admin page through a simple RESTful api and Javascript. It should be simple, but I ran into a strange problem when each of my requests from javascript returns a 403 authorization error. Please note that this only applies to js. I can hit the url from the browser just fine and do all the basic CRUD stuff.

The code is very simple.

Javascript

 $.ajax({ xhrFields: {withCredentials: true}, type: 'PATCH', url: 'path/to/my/endpoint, data: { aParam: someValue, 'csrfmiddlewaretoken': getCookie('csrftoken') }, success: doSomething, error: doSomething }); 

Python

 class MyObjectDetail(RetrieveUpdateDestroyAPIView): queryset = MyObject.objects.all() serializer_class = MyObjectSerializer authentication_classes = (SessionAuthentication,) permission_classes = (IsAuthenticated,) 

Initially, I suspected that the session identifier was not being sent, and that’s why that's why everything failed due to permissions. However, the session cookie is indeed sent to the ajax POST and is selected by the Django middleware. Django does not start an admin session without problems. However (after a lot of debugging) I traced the rewriting of the user into the dispatch method in the Django Rest Framework - in particular, calling self.initialize_request . After this call returns, my Admin user is unloaded for one of the AnonymouseUser s rest frameworks.

I am completely lost. I spent about 2 hours with the debugger, but still do not understand why my user is replaced. Has anyone come across this before? Am I just doing something wrong?

+6
source share
1 answer

The body of error 403 should contain a friendly message explaining what the problem is, I think in this case you will find that the message complains about the lack of a CSRF token.

Please note that this only applies to js. I can hit the url from the browser just fine and do all the basic CRUD stuff.

There are only a few things between JS and the browser, and none of them are directly called by the Django REST framework. The one you probably click on is how the CSRF is handled in AJAX requests: the CSRF token should be passed through the header . Now that means you are changing your JavaScript to

 function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } function addCsrfToken (xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } $.ajax({ xhrFields: {withCredentials: true}, type: 'PATCH', url: 'path/to/my/endpoint', data: { aParam: someValue }, success: doSomething, error: doSomething, beforeSend: addCsrfToken }); 

Note that if the Django documentation recommends setting this header globally, it explicitly prohibits the sending of tokens in cross-origin requests. It looks like (from withCredentials ) in your code that you are accessing an API in another domain.

Django does not start an administrator session without problems.

This is most likely because clicking a page in your browser does not trigger a CSRF check, and the API you are viewing for viewing processes the CSRF for you.

After this call comes back, my Admin user will switch places for one of the AnonymouseUser rest frameworks.

The Django REST framework only works with an anonymous user in one place and when in the absence of authentication. Thus, although your request can be authenticated through Django, it probably does not authenticate through the Django REST framework.

0
source

Source: https://habr.com/ru/post/986933/


All Articles