example - django rest framework with django 2
¿Cómo hacer un POST simple JSON usando Django REST Framework? CSRF token missing or incorrect (9)
Agradecería que alguien me mostrara cómo hacer una solicitud POST simple utilizando JSON con el marco Django REST. No veo ningún ejemplo de esto en el tutorial en ninguna parte?
Aquí está mi objeto de modelo de rol que me gustaría publicar. Este será un nuevo rol que me gustaría agregar a la base de datos pero obtengo un error de 500.
{
"name": "Manager",
"description": "someone who manages"
}
Aquí está mi solicitud de curl en un indicador de terminal de bash:
curl -X POST -H "Content-Type: application/json" -d ''[
{
"name": "Manager",
"description": "someone who manages"
}]''
http://localhost:8000/lakesShoreProperties/role
La URL
http://localhost:8000/lakesShoreProperties/roles
SÍ trabaja con una solicitud GET, y puedo desplegar todos los roles en la base de datos, pero parece que no puedo crear nuevos Roles. No tengo permisos establecidos Estoy usando una vista estándar en views.py
class RoleDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Role.objects.all()
serializer_class = RoleSerializer
format = None
class RoleList(generics.ListCreateAPIView):
queryset = Role.objects.all()
serializer_class = RoleSerializer
format = None
Y en mi urls.py
para esta aplicación, las asignaciones relevantes de url - view son correctas:
url(r''^roles/$'', views.RoleList.as_view()),
url(r''^role/(?P<pk>[0-9]+)/$'', views.RoleDetail.as_view()),
Mensaje de error es:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
¿Qué está pasando aquí y cuál es la solución para esto? ¿Localhost es una solicitud cruzada? He agregado @csrf_exempt
a RoleDetail
y a RoleList
pero no parece cambiar nada. ¿Se puede agregar este decorador a una clase o se debe agregar a un método? Al @csrf_exempt
decorar @csrf_exempt
, mi error se convierte en:
Request Method: POST
Request URL: http://127.0.0.1:8000/lakeshoreProperties/roles/
Django Version: 1.5.1
Exception Type: AttributeError
Exception Value:
''function'' object has no attribute ''as_view''
Luego deshabilité CSRF a través de toda la aplicación, y ahora recibo este mensaje:
{"non_field_errors": ["Datos no válidos"]} cuando mi objeto JSON sé que es válido json. No es un error de campo, pero estoy atrapado aquí mismo.
Bueno, resulta que mi json no era válido?
{
"name": "admin",
"description": "someone who administrates"
}
vs
[
{
"name": "admin",
"description": "someone who administrates"
}
]
Tener los corchetes adjuntos [] hace que la solicitud POST falle. Pero al usar el validador jsonlint.com, ambos de mis objetos json validan.
Actualización : El problema fue enviar el POST con PostMan, no en el back-end. Ver https://stackoverflow.com/a/17508420/203312
Bien, ahora, por supuesto, recupero lo que dije. CSRF funciona según lo previsto.
Estaba haciendo una solicitud POST usando un complemento de Chrome llamado POSTMAN. Mi solicitud POST falla con CSRF habilitado.
Pero una solicitud POST de curl usando
curl -X POST -H "Content-Type: application/json" -d ''
{
"name": "Manager",
"description": "someone who manages"
}'' http://127.0.0.1:8000/lakeshoreProperties/roles/
funciona bien ... Tuve que quitar los frenos, es decir, [], y asegurarme de que haya una barra después de los roles ''s'', es decir, roles /, y csrf habilitado no arrojó ningún error.
No estoy seguro de cuál es la diferencia entre llamar usando POSTMAN vs usar curl, pero POSTMAN se ejecuta en el navegador web, que es la mayor diferencia. Dicho esto, deshabilité csrf para toda la clase RoleList pero una solicitud idéntica funciona con Curl, pero falla con POSTMAN.
CSRF está exento por defecto en Django REST Framework. Por lo tanto, la solicitud POST de curl funciona bien. La llamada de solicitud POSTMAN devolvió CSRF incorrecto porque POSTMAN incluyó token csrf si se encuentra en Cookies. Puede resolver esto limpiando las cookies.
Como dijiste, tu URL era
http://localhost:8000/lakesShoreProperties/roles
El cartero tiene algunos problemas con localhost. En su lugar, enviar el POST a 127.0.0.1:8000/your-api/endpoint
fue el truco para mí.
Es desde la configuración de tu marco REST. en su archivo settings.py
, su REST_FRAMEWORK
debe tener lo siguiente.
REST_FRAMEWORK = {
''DEFAULT_AUTHENTICATION_CLASSES'': (
''rest_framework.authentication.TokenAuthentication'',
),
''DEFAULT_PERMISSION_CLASSES'': (
''rest_framework.permissions.AllowAny'',
),
}
Esto establecerá su Marco REST para usar la autenticación token en lugar de la autenticación csrf. Y al establecer el permiso para AllowAny
, puede autenticarse solo donde lo desee.
Para dar una actualización sobre el estado actual y resumir algunas respuestas:
Las solicitudes de AJAX que se realicen dentro del mismo contexto que la API con la que interactúan normalmente usarán
SessionAuthentication
. Esto garantiza que una vez que un usuario haya iniciado sesión, cualquier solicitud AJAX realizada se puede autenticar utilizando la misma autenticación basada en sesión que se utiliza para el resto del sitio web.Las solicitudes AJAX que se realizan en un sitio diferente de la API con la que se están comunicando normalmente necesitarán un esquema de autenticación no basado en sesiones, como
TokenAuthentication
.
Por lo tanto, las respuestas que recomiendan sustituir SessionAuthentication
con TokenAuthentication
pueden resolver el problema, pero no son necesariamente totalmente correctas.
Para protegerse contra este tipo de ataques, debe hacer dos cosas:
Asegúrese de que las operaciones HTTP ''seguras'', como
GET
,HEAD
yOPTIONS
no puedan usarse para alterar ningún estado del lado del servidor.Asegúrese de que cualquier operación HTTP ''insegura'', como
POST
,PUT
,PATCH
yDELETE
, siempre requiera un token CSRF válido. Si usaSessionAuthentication
, deberá incluir tokens CSRF válidos para cualquier operaciónPOST
,PUT
,PATCH
oDELETE
.Para realizar solicitudes AJAX, debe incluir el token CSRF en el encabezado HTTP , como se describe en la documentación de Django.
Por lo tanto, es importante que csrf esté incluido en el encabezado, como por ejemplo sugiere esta respuesta .
Referencia: Trabajando con AJAX, CSRF y CORS, documentación del framework Django REST .
Probablemente necesites enviar el token CSRF con tu solicitud. Consulte https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax
Actualización: como ya intentó eximir CSRF, quizás esto podría ser útil (según la versión de Django que esté utilizando): https://.com/a/14379073/977931
También puede desactivar el CSRF para crear su propio middleware:
class DisableCSRF(object):
def process_request(self, request):
setattr(request, ''_dont_enforce_csrf_checks'', True)
E incluya este middleware en su archivo settings.py en MIDDLEWARE_CLASSES.
si ha establecido permiso AllowAny
y se enfrenta con el problema csrf
REST_FRAMEWORK = {
''DEFAULT_PERMISSION_CLASSES'': [
''rest_framework.permissions.AllowAny''
]
}
a continuación, colocar siguiente en settings.py
resolverá el problema
REST_SESSION_LOGIN = False