Django-Rest + React 前端:CORS 问题

Posted

技术标签:

【中文标题】Django-Rest + React 前端:CORS 问题【英文标题】:Django-Rest + React Frontend : CORS issue 【发布时间】:2021-10-24 07:31:16 【问题描述】:

我有一个 Django REST 后端(目前以 http://localhost:8000 运行)和一个 React 前端(在 http://localhost:3000 上),我正在努力让跨域认证工作。

我在这里读到的大多数解决方案(例如,参见1 或2)都是针对CORS_ORIGIN_ALLOW_ALL = TrueCORS_ALLOWED_ORIGINS = [*],但这不是我想做的事情。 我希望它对生产安全,并了解如何正确设置 csrf 身份验证。

错误信息:

在 Django 控制台中我看到:

[24/Aug/2021 13:48:18] "OPTIONS /calc/ HTTP/1.1" 200 0
Forbidden (CSRF cookie not set.): /calc/

在我的浏览器中:

Failed to load resource: the server responded with a status of 403 (Forbidden)

文件:

Django REST API:

我已经安装了django-cors-headers

settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'maapi', # This is my app
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware', # Cors header are here
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

[...]

CORS_ORIGIN_ALLOW_ALL = False

CORS_ALLOWED_ORIGINS = [
    "http://127.0.0.1:3000",
    "http://localhost:3000",
]

CORS_ALLOW_CREDENTIALS = True

CSRF_TRUSTED_ORIGINS = [
    "http://127.0.0.1:3000",
    "http://localhost:3000",
]
maapi/views.py
class Calc(View):
    """
    Run a static simulation.
    """

    def post(self, request, *args, **kwargs):
        rjson = json.loads(request.body)
        try:
            # do things
            return JsonResponse(results)
        except Exception as e:
            return e, 500
urls.py
from maapi import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('calc/', views.Calc.as_view(), name='calc'),
    # path('calc/', ensure_csrf_cookie(views.Calc.as_view()), name='calc'), # I tried this one too without more success
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('', include(router.urls)),
]

反应前端:

我用的是教程here。

CrsfToken.js
import React from 'react';

function getCookie(name) 
    let cookieValue = null;

    if (document.cookie && document.cookie !== '') 
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) 
            const 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;


const csrftoken = getCookie('csrftoken');

const FormCsrfToken = () => 
    return (
        <input name="csrfmiddlewaretoken" value=csrftoken type="hidden" />
    );
;

export default FormCsrfToken;
export  csrftoken 
App.js
import  csrftoken  from './CsrfToken';

function App() 

  [...]

  const getdata = () => 
    setFetching(true);
    const bod = 
      // Things
    ;
    fetch("http://localhost:8000/calc/", 
      method: "POST",
      credentials: 'include',
      mode: 'cors',
      headers: 
        'Accept': 'application/json',
        "Content-Type": "application/json",
        'X-CSRFToken': csrftoken,
      ,
      body: JSON.stringify(bod),
    )
      .then((response) => 
        return response.json();
      )
      .then((d) => 
        // Do things
      )
      .catch((object) => 
        setFetching(false);
        openNotification();
      );
  ;

你能发现缺少的东西吗?

【问题讨论】:

【参考方案1】:

我已经解决了:

只需将您的 CSRF_TRUSTED_ORIGINS 更改为:

 CSRF_TRUSTED_ORIGINS = [
    "127.0.0.1:3000",
    "localhost:3000",
]

还有一件事,不要在请求中发送csrftoken。你不需要它。你可以删除它。

【讨论】:

谢谢,我试过了,但没有任何改变,我仍然有同样的问题Forbidden (CSRF cookie not set.): /calc/(前端有或没有csrftoken)。 尝试从您的 fetch 请求中删除 credentials:'include' 并从您的 settings.py 中删除 CORS_ALLOW_CREDENTIALS 谢谢,但在从请求中删除凭据和 CORS_ALLOW_CREDENTIALS 时仍然出现相同的错误 Forbidden (CSRF cookie not set.): /calc/

以上是关于Django-Rest + React 前端:CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 angularjs 进行 django-rest 分页

使用 angular 向 django-rest 发送 DELETE 请求被解释为 OPTIONS

markdown Fluxo django-rest

使用 django-rest 框架中的 GET 方法将 url 作为参数传递?

使用 django-allauth 和 django-rest 框架

如何使用模型序列化器在 django-rest 中序列化一对多关系?