CSRF 令牌上的 Django 错误

Django bug on CRSF token

我将 django 用作后端的 Web API,将 React JS 用作前端的 Web UI。用户将从网络 UI 注册,这将向 django 发送 POST 请求以注册用户详细信息。我想用 CSRF 保护注册视图。因此,我提出了以下步骤。

首先,加载注册页面后,我会发出一个虚拟 GET 请求,以使用以下代码存储 csrf 令牌。

handleSend(){
  let req = {
    url: 'http://localhost:9000/vcubes/retrieve_token/',
    method : 'GET',
    withCredentials: true
  }
  axios(req)
}

然后,当用户提交注册表单时,将触发另一个 POST 请求。

const data = JSON.stringify({
        'first_name': this.state.first_name,
        'last_name': this.state.last_name,
        'email': this.state.email,
        'contact_number': this.state.contact_number,
        'password1': this.state.password1,
        'password2': this.state.password2,
      })
      let req = {
        url: 'http://localhost:9000/vcubes/signup/',
        method : 'POST',
        headers: {
                'Content-Type': 'text/plain'
        },
        data: data
      }
      axios.defaults.headers.common['X-CSRF-TOKEN'] = this.getCookie('vcubes')

使用上面的代码,一个 OPTIONS 将首先发送到 django,然后在 django 发送回一个 200 OK 之后,然后将触发实际的 POST 请求。

惊喜! Django 声明我没有设置 CSRF cookie。

Forbidden (CSRF cookie not set.): /vcubes/signup/
[30/Oct/2017 01:30:48] "POST /vcubes/signup/ HTTP/1.1" 403 2857

我的settings.py在下面。 (我只展示了一些CORS和CSRF的相关代码)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'corsheaders',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'custom_user',
    'vcubes',
]

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

CSRF_TRUSTED_ORIGINS = (
    'localhost:8000',
    '127.0.0.1:8000'
)

CSRF_COOKIE_NAME = 'vcubes'

CSRF_HEADER_NAME = 'HTTP_X_CSRF_TOKEN'

CORS_ORIGIN_ALLOW_ALL = True

CORS_ALLOW_CREDENTIALS = True

CORS_ORIGIN_WHITELIST = (
    'localhost:8000',
    '127.0.0.1:8000'
)


CORS_ALLOW_HEADERS = (
    'access-control-allow-credentials',
    'access-control-allow-origin',
    'access-control-request-method',
    'access-control-request-headers',
    'accept',
    'accept-encoding',
    'accept-language',
    'authorization',
    'connection',
    'content-type',
    'dnt',
    'credentials',
    'host',
    'origin',
    'user-agent',
    'X-CSRF-TOKEN',
    'X-CSRFToken',
    'x-requested-with',
)

在views.py

@ensure_csrf_cookie
def retrieve_token(request):
    return HttpResponse(status=200)

def signup(request):
    print request.META
    form = UserCreationForm(json.loads(request.body))
    # user = form.save(commit=False)
    # user.is_active = False
    # user.save()
    #
    # mail_subject = 'Activate your account.'
    # message = render_to_string('acc_active_email.html', {
    #     'name': user.get_full_name(),
    #     'domain': 'localhost:9000',
    #     'uid': urlsafe_base64_encode(force_bytes(user.pk)),
    #     'token': account_activation_token.make_token(user),
    # })
    # to_email = user
    # email = EmailMessage(
    #     mail_subject, message, to=[to_email]
    # )
    # email.send()
    return HttpResponse(status=200)

我花了一整天的时间从 google 和 Whosebug 找出问题,但几乎没有得到任何帮助。请赐教!

您的 post 请求缺少 withCredentials: true,这意味着您的 CSRF cookie 未随请求一起发送。