Django Rest Framework не распознает файл cookie CSRF, отправленный из приложения React с использованием Axios - PullRequest
0 голосов
/ 08 января 2019

Я уже много лет являюсь бэкэнд-разработчиком, но теперь я хочу изучать и внешний интерфейс, поэтому для начала я выбрал React в качестве основы веб-интерфейса. Я потратил два дня на обучение отправке запросов из приложения React с использованием Axios в Django Rest Framework бэкэнд, и столкнулся с этим csrf cookie выпуск. Я уже опубликовал несколько вопросов, и, наконец, смог отправить правильно сформированный запрос, принятый бэкэндом ... только для получения ошибки Forbidden (CSRF token missing or incorrect.).

Полагаю, мой подход к получению и использованию токена csrf может быть неправильным, поэтому я был бы признателен, если бы вы указали мою ошибку и научили ее ее решать.

Сначала я отправляю запрос GET на сервер с единственной целью - получить токен csrf (что я делаю) и устанавливаю cookie на такой токен:

class App extends Component {
  render() {
    const axios = require('axios');
    axios.get('http://127.0.0.1:8000/es/api/hand_shake/')
    .then(function (response) {
      Cookies.set('csrftoken', response['data']['cookie']);
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })

    return (
      <div className="App">
        <LoginModal />
      </div>
    );
  }
}

export default App;

Во-вторых, в другом модуле я получаю токен из куки и использую его в POST запросе:

handleClick() {
    const axios = require('axios');
    var csrfCookie = Cookies.get('csrftoken');
    console.log(csrfCookie)
    axios.post('http://127.0.0.1:8000/es/api-auth/login/',
      {
        next: '/',
        username: 'admin@admin.com',
        password: 'Cancun10!',
      },
      {
        headers: {
          'x-xsrf-token': csrfCookie,
        },
        withCredentials: true,
      }
    )
    .then(function (response) {
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })
  }

Наконец-то я получил бэкэнд для принятия запроса, но я получаю сообщение об ошибке Forbidden (CSRF token missing or incorrect.).

Правильно ли получить маркер так, как я это делаю, а затем использовать его так, как я пытаюсь?

1 Ответ

0 голосов
/ 10 января 2019

Единственное решение, которое я нашел, - освободить процесс входа в систему от проверки csrf, но мне пришлось отказаться от Django Rest Framework функциональности аутентификации по умолчанию (если кто-нибудь знает, как это сделать с DRF аутентификация по умолчанию, пожалуйста, поделитесь) и реализовать мой собственный вид аутентификации.

Я создал ViewSet и украсил его csrf_exempt, например:

from django.views.decorators.csrf import csrf_exempt

class LoginViewSet(viewsets.ViewSet):
    permission_classes = ()

    @csrf_exempt
    def post(self, request):
        from PhotosManagerApp.email_backend import EmailBackend

        email_backend_instance = EmailBackend()
        user = email_backend_instance.authenticate(request, username=request.data['username'], password=request.data['password'])
        if user:
            try:
                usr_token = Token.objects.get(user=user)
            except:
                usr_token = None
        else:
            usr_token = None

        return Response({'token': str(usr_token)})

Вы также должны украсить свой вид в urls.py:

path('login/', csrf_exempt(views.LoginViewSet.as_view({'post': 'post'}))),

У меня было много проблем с Django settings.py, пока я не нашел правильную конфигурацию:

from corsheaders.defaults import default_headers

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = default_headers + (
    'xsrfheadername',
    'xsrfcookiename',
    'content-type',
    'x-csrftoken',
)

CORS_ORIGIN_ALLOW_ALL = True
CSRF_COOKIE_NAME = "csrftoken"

У меня было много неприятностей, пока я не обнаружил, что мне нужно добавить default_headers к CORS_ALLOW_HEADERS.

Теперь просто отправьте запрос с withCredentials = false:

handleClick() {
    const axios = require('axios');
    //axios.defaults.withCredentials = true;
    axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
    axios.defaults.xsrfCookieName = "csrftoken";
    axios.post('http://127.0.0.1:8000/es/api/login/',
      {
        username: 'admin@admin.com',
      },
    )
    .then(function (response) {
      Cookies.set('token', "Token ".concat(response.data.token), {"expires": 10})
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })
  }

Вот что у меня сработало.

...