django reactjs redux django-csrf axios

CSRF con Django, React+Redux usando Axios



reactjs django-csrf (7)

Descubrí que axios.defaults.xsrfCookieName = "XCSRF-TOKEN"; y CSRF_COOKIE_NAME = "XCSRF-TOKEN"

NO FUNCIONA EN APPLE Safari en Mac OS

La solución para MAC Safari es fácil, simplemente cambie XCSRF-TOKEN csrftoken a csrftoken

Por lo tanto, en código js debe ser:

import axios from ''axios''; axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"; axios.defaults.xsrfCookieName = "csrftoken";

En settings.py:

CSRF_COOKIE_NAME = "csrftoken"

Este es un proyecto educativo, no para producción. No tenía la intención de tener inicios de sesión de usuarios como parte de esto.

¿Puedo hacer llamadas POST a Django con un token CSRF sin tener que iniciar sesión como usuario? ¿Puedo hacer esto sin usar jQuery? Estoy fuera de mi profundidad aquí, y seguramente estoy confundiendo algunos conceptos.

Para el lado de JavaScript, encontré este paquete redux-csrf . No estoy seguro de cómo combinarlo con mi acción POST usando Axios:

export const addJob = (title, hourly, tax) => { console.log("Trying to addJob: ", title, hourly, tax) return (dispatch) => { dispatch(requestData("addJob")); return axios({ method: ''post'', url: "/api/jobs", data: { "title": title, "hourly_rate": hourly, "tax_rate": tax }, responseType: ''json'' }) .then((response) => { dispatch(receiveData(response.data, "addJob")); }) .catch((response) => { dispatch(receiveError(response.data, "addJob")); }) } };

En el lado de Django, he leído esta documentación en CSRF, y this en general trabajando con vistas basadas en clase.

Aquí está mi opinión hasta ahora:

class JobsHandler(View): def get(self, request): with open(''./data/jobs.json'', ''r'') as f: jobs = json.loads(f.read()) return HttpResponse(json.dumps(jobs)) def post(self, request): with open(''./data/jobs.json'', ''r'') as f: jobs = json.loads(f.read()) new_job = request.to_dict() id = new_job[''title''] jobs[id] = new_job with open(''./data/jobs.json'', ''w'') as f: f.write(json.dumps(jobs, indent=4, separators=('','', '': ''))) return HttpResponse(json.dumps(jobs[id]))

Intenté usar el decorador csrf_exempt solo para no tener que preocuparme por esto por ahora, pero parece que no es así como funciona.

He añadido {% csrf_token %} a mi plantilla.

Este es mi método getCookie (robado de documentos Django):

function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '''') { var cookies = document.cookie.split('';''); for (var i = 0; i < cookies.length; i++) { var cookie = cookies[i].trim(); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + ''='')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }

He leído que necesito cambiar la información CSRF de Axios:

var axios = require("axios"); var axiosDefaults = require("axios/lib/defaults"); axiosDefaults.xsrfCookieName = "csrftoken" axiosDefaults.xsrfHeaderName = "X-CSRFToken"

¿Dónde getCookie(''csrftoken'') el token real, el valor que obtengo al llamar a getCookie(''csrftoken'') ?


En realidad, hay una manera muy fácil de hacer esto.

Agregue axios.defaults.xsrfHeaderName = "X-CSRFToken"; a la configuración de la aplicación y luego establezca CSRF_COOKIE_NAME = "XSRF-TOKEN" en su archivo settings.py. Funciona de maravilla.


Esta configuración me funciona sin problemas Config axios CSRF django

import axios from ''axios'' /** * Config global for axios/django */ axios.defaults.xsrfHeaderName = "X-CSRFToken" axios.defaults.xsrfCookieName = ''csrftoken'' export default axios


Hay tres maneras. Puede incluir manualmente el token en el encabezado de cada llamada de axios, puede establecer xsrfHeaderName de xsrfHeaderName en cada llamada, o establecer un xsrfHeaderName predeterminado.

1. Añadiéndolo manualmente.

Digamos que tienes el valor del token almacenado en una variable llamada csrfToken . Establece los encabezados en tu llamada axios:

// ... method: ''post'', url: ''/api/data'', data: {...}, headers: {"X-CSRFToken": csrfToken}, // ...

2. Estableciendo xsrfHeaderName en la llamada:

Agrega esto:

// ... method: ''post'', url: ''/api/data'', data: {...}, xsrfHeaderName: "X-CSRFToken", // ...

Luego, en su archivo settings.py , agregue esta línea:

CSRF_COOKIE_NAME = "XSRF-TOKEN"

3. Estableciendo encabezados por defecto [1]

En lugar de definir el encabezado en cada llamada, puede establecer encabezados predeterminados para axios.

En el archivo donde está importando axios para realizar la llamada, agregue esto debajo de sus importaciones:

axios.defaults.xsrfHeaderName = "X-CSRFToken";

Luego, en su archivo settings.py , agregue esta línea:

CSRF_COOKIE_NAME = "XSRF-TOKEN"

EDITAR : Aparentemente funciona ligeramente diferente con Safari [2]

[1] Del comment Dave Merwin.

La confusión:

Django docs

Primero, todo el pasaje de los documentos de Django al que James Evans hizo referenced :

... en cada XMLHttpRequest, establezca un encabezado X-CSRFToken personalizado al valor del token CSRF. Esto suele ser más fácil, ya que muchos marcos de JavaScript proporcionan enlaces que permiten establecer encabezados en cada solicitud.

Como primer paso, debes obtener el token CSRF. La fuente recomendada para el token es la cookie csrftoken, que se configurará si ha habilitado la protección CSRF para sus vistas como se describe anteriormente.

Nota

La cookie de token CSRF se denomina csrftoken de forma predeterminada, pero puede controlar el nombre de la cookie a través de la configuración CSRF_COOKIE_NAME.

El nombre del encabezado CSRF es HTTP_X_CSRFTOKEN de forma predeterminada, pero puede personalizarlo usando la configuración CSRF_HEADER_NAME.

Axios Docs

Esto es de los documentos de Axios . Indica que establece el nombre de la cookie que contiene el csrftoken y el nombre del encabezado aquí:

// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token xsrfCookieName: ''XSRF-TOKEN'', // default // `xsrfHeaderName` is the name of the http header that carries the xsrf token value xsrfHeaderName: ''X-XSRF-TOKEN'', // default

Condiciones

Como se indica en mi pregunta, puede acceder a las cookies con document.cookie . La única cookie que tengo es el token CSRF que puse en la plantilla de Django. Aquí hay un ejemplo:

csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU

Hay algunos conceptos que se presentan en esos documentos que se vuelven confusos:

  • El nombre de la cookie que contiene el token CSRF. En Django esto es por defecto csrftoken , que está en el lado izquierdo del signo igual en la cookie.
  • El token real. Esto es todo en el lado derecho del signo igual en la cookie.
  • El encabezado http que lleva el valor del token.

Cosas que probé que no funcionaron: 1 , 2


La "manera fácil" casi me funcionó. Esto parece funcionar:

import axios from ''axios''; axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"; axios.defaults.xsrfCookieName = "XCSRF-TOKEN";

Y en el archivo settings.py:

CSRF_COOKIE_NAME = "XCSRF-TOKEN"


Para mí, django no estaba escuchando los encabezados que estaba enviando. Podría acurrucarme en la api pero no pude acceder con axios. Echa un vistazo al paquete cors-headers ... podría ser tu nuevo mejor amigo.

Lo arreglé instalando django-cors-headers

pip install django-cors-headers

Y luego añadiendo

INSTALLED_APPS = ( ... ''corsheaders'', ... )

y

MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10 ... ''corsheaders.middleware.CorsMiddleware'', ''django.middleware.common.CommonMiddleware'', ... ]

en mi configuración.py

también tenía

ALLOWED_HOSTS = [''*''] CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_CREDENTIALS = True CORS_EXPOSE_HEADERS = ( ''Access-Control-Allow-Origin: *'', )

en mi settings.py aunque eso es probablemente una exageración


Podría agregar el token CSRF provisto por Django manualmente en todas sus solicitudes de publicación, pero eso es molesto.

De los documentos de Django :

Si bien el método anterior ( configuración manual del token CSRF ) se puede usar para las solicitudes POST de AJAX, tiene algunos inconvenientes: debe recordar pasar el token CSRF como datos POST con cada solicitud POST. Por este motivo, existe un método alternativo: en cada XMLHttpRequest, establezca un encabezado X-CSRFToken personalizado al valor del token CSRF. Esto suele ser más fácil, ya que muchos marcos de JavaScript proporcionan enlaces que permiten establecer encabezados en cada solicitud.

Los documentos tienen un código que puede usar para extraer el token CSRF de la cookie del token CSRF y luego agregarlo al encabezado de su solicitud AJAX.