React и Django: CSRF Token не установлен на продакшене, и особенно для метода create
на разработке, куки csrf устанавливались нормально, если они не были доступны на вкладке приложения в dev tool, однако на продакшене, когда я пытаюсь создать новый пост, он говорит мне " CSRF Failed: CSRF token from the 'X-Csrftoken' HTTP header has incorrect length.
".
однако, интрига здесь в том, что при других запросах к посту, например, когда вы входите в систему или регистрируетесь, все работает отлично и прекрасно, так что я решил, что это проблема с методом create
в django (НО с логином, несмотря на то, что логин работает отлично, и что я вхожу, используя аутентификацию на основе сессии, похоже, что session_id и csrf невидимы на вкладке приложения?
Я предполагаю, что это потому, что сайт находится на производстве, и по соображениям безопасности он не может показывать session_id там.
Однако, когда я пытаюсь заглянуть на вкладку network после того, как я попытался создать сообщение и потерпел неудачу, это выглядит так, как будто x-csrftoken
это undefined
но есть еще один ключ cookie
, который включает в себя и csrftoken
и session_id
обратите внимание, что это происходит только на продакшене, я никогда не сталкивался с такой проблемой на сервере разработки, и посмотрите на код settings.py после кода просмотра для большего прояснения (я добавил https://somedomain.com для домена, которому нужен разрешенный токен csrf)
views.py:
class CheckAuthenticated(views.APIView):
def get(self, request):
if request.user.is_authenticated:
return Response("Authenticated")
else:
return Response("Not Authenticated",status=401)
class PostView(viewsets.ModelViewSet):
serializer_class = serializer.PostSerializer
def get_queryset(self):
queryset = models.Post.objects.all()
return queryset
@method_decorator(ensure_csrf_cookie)
def create(self,request):
authentication_classes = [SessionAuthentication]
permissions_classes = [IsAuthenticated]
post = serializer.PostSerializer(data=request.data)
if post.is_valid():
title = post.data['title']
description = post.data['description']
models.Post.objects.create(title=title,description=description,user=User.objects.first())
return Response("post created successfully.")
return Response("post creation failed.")
Теперь в frontend:
let handleSubmit = (e)=>{
e.preventDefault()
console.log(Cookies.get('csrftoken'))
axios.post('https://somedomain.com/posts/',post,{withCredentials:true,headers:{'X-CSRFToken':Cookies.get('csrftoken')}}).then((res)=>{
console.log(res.data)
}).catch((e)=>{
console.log(e.response.data)
console.log(Cookies.get('csrftoken'))
})
}
useEffect(()=>{
axios.get('http://127.0.0.1:8000/posts/').then((res)=>{
setPostList(res.data)
})
axios.get('http://127.0.0.1:8000/csrf/',{headers:{Authorization:null},withCredentials:true})
},[])
Код settings.py:
ALLOWED_HOSTS = ['*']
ACCESS_CONTROL_ALLOW_ORIGIN = '*'
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_METHODS = '*'
ACCESS_CONTROL_ALLOW_HEADERS = '*'
'''
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_PATH = '/'
'''
CSRF_COOKIE_SAMESITE = 'Strict'
CSRF_TRUSTED_ORIGINS = [ "http://127.0.0.1:3000",'http://127.0.0.1:8000','https://somedomain.com/']
SECURE_SSL_REDIRECT = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 60
CUSTOM_HEADERS = (
'Access-Control-Allow-Origin',
'Token',
'User-Type'
)
CORS_ALLOW_HEADERS = default_headers + CUSTOM_HEADERS
CSRF_COOKIE_SAMESITE = 'none'
Я забыл ответить на этот вопрос, в основном фронтенд обслуживается на другом поддомене, поэтому правило cookie samesite должно быть установлено на None
, в settings.py
: измените CSRF_COOKIE_SAMESITE = 'Strict'
на CSRF_COOKIE_SAMESITE = 'None'
также, если вы используете аутентификацию на основе сессий (которая по умолчанию требует токен csrf для почтовых запросов, читайте документацию здесь), не забудьте добавить:
SESSION_COOKIE_SAMESITE = 'None'
в settings.py