【问题标题】:post to django API returns 403 (Forbidden) when authenticated, but able post when not authenticated发布到 django API 在经过身份验证时返回 403(禁止),但在未经过身份验证时可以发布
【发布时间】:2021-02-05 14:08:46
【问题描述】:

我正在构建一个应用程序,其工作方式如下:

  • 用户在 html 表单上填写数据并提交。
  • 数据发布到 API(通过 Fetch)。

这个应用程序使用 django,django rest 框架使用纯 html 和 vanilla jav 我的问题是,当用户在 API/后端进行身份验证时,我无法发布。它返回 403。但是,当我未通过身份验证时,我可以从表单中发布数据。

这是 form.html 上的 JS,它将数据发布到 API:

<script>
  console.log('js linked')
  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;
  }
  var csrftoken = getCookie('csrftoken');

console.log(csrftoken)

  function post_report(event) {
    event.preventDefault();
    var contact_email = document.getElementById("contact_email").value
    var contact_number = document.getElementById("contact_number").value
    var date_time = document.getElementById("date_time").value
    var location = document.getElementById("location").value
    var description = document.getElementById("description").value
    console.log(contact_email + ' ' + description)


    fetch("http://127.0.0.1:8000/api/Flight_Safety_Reports/",{
      method: "POST",
      mode: 'same-origin',
      headers:{
        "Accept": "application/json",
        'Content-Type':'application/json',
        'X-CSRFToken': csrftoken
      },
      body: JSON.stringify({
        contact_email:contact_email,
        contact_number:contact_number,
        date_time:date_time,
        location:location,
        description:description

      })
    })
    .then(response =>console.log(response))

    alert('report submitted')

  }

</script>

views.py

from app_reports.models import (
FlightSafetyReport
)

from .serializers import (
FlightSafetyReportSerializer
)

class FlightSafetyReportViewSet(viewsets.ModelViewSet):

    serializer_class = FlightSafetyReportSerializer
    queryset = FlightSafetyReport.objects.all()

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'crispy_forms',
    'bootstrap4',

    'rest_framework',
    'corsheaders',
    'articles',
    'user_api',
    'app_sandbox',


    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',

    'rest_auth',
    'rest_auth.registration',
    'rest_framework.authtoken',

]

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

ROOT_URLCONF = 'djreact.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BUILD_DIR, BACKEND_TEMPLATES_DIR],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'djreact.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}


# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'

REST_FRAMEWORK = {
    # Use Django's standard `django.contrib.auth` permissions,
    # or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
   'rest_framework.permissions.AllowAny',
]
}

CORS_ORIGIN_ALLOW_ALL = True


STATICFILES_DIRS = [os.path.join(BUILD_DIR,'static')]


CSRF_COOKIE_NAME = "XSRF-TOKEN"

重新迭代,当我没有登录到 api 时/当我没有登录到 django-admin 时,我可以发帖。登录时出现 403 禁止错误。

【问题讨论】:

  • 您是否尝试过使用$.ajax()。我在获取时遇到了这个问题。我发现当我使用fetch 发布数据时,我没有通过身份验证,但是当我使用$.ajax() 时,它对我进行了身份验证。
  • 我刚试过 ajax(和 axios)。当我通过身份验证时,它们都返回了 403 错误。未认证时,ajax返回400,表示可以post,但数据不正确。 axios返回403。我不会继续使用ajax,因为如果代码正确并且有正确的请求,它仍然会在验证时返回403错误。
  • 如何向后端进行身份验证。你使用api-auth/ 端点吗?
  • 我使用 rest-auth.urls

标签: django fetch


【解决方案1】:

这是我认为您的请求所发生的情况。问题可能是您传递了无效的 csrftoken。我在我这边创建了你的代码的副本,它可以工作。当我将 csrftoken 值更改为某个随机值时,它开始给我403 错误。如下图所示。

var csrftoken = getCookie('csrftoken');
    csrftoken = "blacjcjsjsjss";

然后它在控制台中给出 403 Forbidden 错误。如果我删除csrftoken = "blacjcjsjsjss"; 行,它会再次开始工作。我要说的是您的 csrftoken 值有些错误。您需要确保获得正确的 crsftoken。

【讨论】:

  • 有趣。这是否意味着在这个 csrftoken 被认证之间存在一些奇怪的交互?
  • 我发现了问题。它在您的 settings.py 文件中。在您的 settings.py 文件中,您将 csrf cookie 名称指定为 XSRF-TOKEN 此处为 CSRF_COOKIE_NAME = "XSRF-TOKEN"。在您的 javascript 中,您在这里使用错误的名称访问它var csrftoken = getCookie('csrftoken');。您应该使用您在 settings.py 中指定的名称,此处为 var csrftoken = getCookie('XSRF-TOKEN');。这就是为什么你得到403 这是因为你的 csrftoken 无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-25
  • 1970-01-01
  • 2022-01-20
  • 2015-10-12
  • 2018-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多