React和Django:CSRF令牌未在生产上设置,尤其是对于create方法

g6ll5ycj  于 2023-01-03  发布在  Go
关注(0)|答案(1)|浏览(130)

在开发中,如果csrf cookie在dev工具的应用程序选项卡中不可用,它通常会被设置,但是在生产中,每当我试图创建一个新的帖子时,它会告诉我“CSRF Failed: CSRF token from the 'X-Csrftoken' HTTP header has incorrect length.“然而,这里的情节扭曲,是与其他帖子请求,如当您登录或注册时,它工作得很完美,很好,所以我认为这似乎是django中的create方法的问题(但是对于login,即使login工作得很好,并且我使用基于会话的身份验证登录,似乎session_id和csrf在应用程序选项卡中是不可见的?

我认为这是因为网站正在生产,出于安全原因,它不会显示会话ID。
但是,每当我尝试创建帖子失败后查看网络选项卡时,x-csrftoken看起来像undefined

但是,存在另一个称为cookie的密钥,其包括csrftokensession_id

请注意,这只发生在生产中,我从未在开发服务器上遇到过这样的问题,请查看settings.py视图代码后的www.example.com代码以了解更多说明(我为需要允许csrf令牌的域添加了https://somedomain.com
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.")

现在在前端:

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'
pw9qyyiw

pw9qyyiw1#

我忘了回答这个问题,基本上前端是在一个不同的子域服务,所以cookie相同的规则需要设置为None,在settings.py:将CSRF_COOKIE_SAMESITE = 'Strict'更改为CSRF_COOKIE_SAMESITE = 'None'
此外,如果您使用基于会话的身份验证(默认情况下,需要csrf令牌用于发布请求,请阅读此处的文档),请不要忘记添加:SESSION_COOKIE_SAMESITE = 'None'settings.py

相关问题