首页 > 解决方案 > post to django API 在经过身份验证时返回 403 (Forbidden),但在未经过身份验证时可以发布

问题描述

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

这个应用程序使用 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>

视图.py

from app_reports.models import (
FlightSafetyReport
)

from .serializers import (
FlightSafetyReportSerializer
)

class FlightSafetyReportViewSet(viewsets.ModelViewSet):

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

设置.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 禁止错误。

标签: djangofetch

解决方案


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

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

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


推荐阅读