禁止访问(未设置 CSRF cookie。)- Django 4.1 和 React

问题描述 投票:0回答:0

一般信息:

我在 React 应用程序中发帖时遇到以下错误

Forbidden (CSRF cookie not set.)

我看过很多类似的帖子,但它们似乎并没有解决我的问题。我相信我的问题出在我的 React 应用程序上,而不是我的 Django 端,因为我在 GET 请求上确实收到了 200 响应,但是在发布时,我的 React 应用程序无法控制我的 CSRF 令牌。

已注意到,但无法解释:当我在我的 chrome 检查器中检查应用程序时,我没有看到我的 CSRF 设置

http://localhost:3000/

终端响应:

姜戈

System check identified 1 issue (0 silenced).
April 01, 2023 - 22:02:51
Django version 4.1.7, using settings 'core.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
[01/Apr/2023 22:05:05] "GET /accounts/csrf-cookie HTTP/1.1" 200 29
Forbidden (CSRF cookie not set.): /accounts/register/
[01/Apr/2023 22:05:14] "POST /accounts/register/ HTTP/1.1" 403 2870

反应

Note that the development build is not optimized.
To create a production build, use npm run build.

assets by status 1.33 MiB [cached] 17 assets
assets by status 16.9 MiB [emitted]
  assets by chunk 16.9 MiB (name: main)
    asset static/js/bundle.js 16.9 MiB [emitted] (name: main) 1 related asset
    asset main.41b1aa5256b383579099.hot-update.js 4.01 KiB [emitted] [immutable] [hmr] (name: main) 1 related asset
  assets by path *.json 2.03 KiB
    asset asset-manifest.json 2 KiB [emitted]
    asset main.41b1aa5256b383579099.hot-update.json 28 bytes [emitted] [immutable] [hmr]
  asset index.html 680 bytes [emitted]
Entrypoint main 16.9 MiB (25.6 MiB) = static/js/bundle.js 16.9 MiB main.41b1aa5256b383579099.hot-update.js 4.01 KiB 19 auxiliary assets
cached modules 14.5 MiB (javascript) 1.33 MiB (asset) [cached] 862 modules
runtime modules 29.7 KiB 16 modules
./src/components/csrfToken/csrfToken.js 2.44 KiB [built] [code generated]
webpack 5.76.3 compiled successfully in 1803 ms

代码:

settings.py

INSTALLED_APPS = [
    ...
    'corsheaders',
    'rest_framework',
    ...
]
-------------------
CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
    "http://127.0.0.1:3000",
]
CSRF_TRUSTED_ORIGINS = [
    "http://localhost:3000",
    "http://127.0.0.1:3000",
]
CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_NAME = "csrftoken"
-------------------
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [os.path.join(BASE_DIR, '../build')],
        "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",
            ],
        },
    },
]
-------------------
MIDDLEWARE = [
    ...
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...
]
-------------------
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ]
}

views.py

@method_decorator(csrf_protect, name='dispatch')
class SignupView(APIView):
    permission_classes = (permissions.AllowAny, )

    def post(self, request, format=None):
        data = self.request.data

        username = data['username']
        password = data['password']
        re_password  = data['re_password']

        try:
            if password == re_password:
                if User.objects.filter(username=username).exists():
                    return Response({ 'error': 'Username already exists' })
                else:
                    if len(password) < 6:
                        return Response({ 'error': 'Password must be at least 6 characters' })
                    else:
                        user = User.objects.create_user(username=username, password=password)
                        user = User.objects.get(id=user.id)
                        user_profile = StudentProfile.objects.create(user=user, first_name='', last_name='', phone='', city='')

                        return Response({ 'success': 'User created successfully' })
            else:
                return Response({ 'error': 'Passwords do not match' })
        except:
                return Response({ 'error': 'Something went wrong when registering account' })


@method_decorator(ensure_csrf_cookie, name='dispatch')
class GetCSRFToken(APIView):
    permissions_classes = {permissions.AllowAny, }

    def get(self, request, format=None):
        return Response({'success': 'CSRF Cookie set'})

csrfToken.js

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const CSRFToken = () => {
    const [csrftoken, setcsrftoken] = useState('');

    const getCookie = (name) => {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            let cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                let cookie = cookies[i].trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    let csrfToken = getCookie('csrftoken');

    useEffect(() => {
        const fetchData = async () => {
            try {
                await axios.get(`${process.env.REACT_APP_API_URL}/accounts/csrf-cookie`);
                console.log('success');
            } catch (err) {

            }
        };

        fetchData();
        setcsrftoken(getCookie('csrfToken'));
    }, []);

    return (
        <input type='hidden' name='csrfmiddlewaretoken' value={csrfToken} />
    );
};

export default CSRFToken;

src/actions/auth.js

import axios from "axios";
import Cookies from "js-cookie";
import { REGISTER_SUCCESS, REGISTER_FAIL } from "./types";

export const register = (username, password, re_password) => async dispatch => {
  const config = {
      headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'X-CSRFToken': Cookies.get('csrftoken')
      }
  };

  console.log(config);

  const body = JSON.stringify({ username, password, re_password });

  try {
      const res = await axios.post(`${process.env.REACT_APP_API_URL}/accounts/register`, body, config);

      if (res.data.error) {
          dispatch({
              type: REGISTER_FAIL
          });
      } else {
          dispatch({
              type: REGISTER_SUCCESS
          });
      }
  } catch (err) {
      dispatch({
          type: REGISTER_FAIL
      });
  }
};

src/reducers/auth.js

import { REGISTER_SUCCESS, REGISTER_FAIL } from "actions/types";

const initialState = {
  isAuthenticated: null,
  username: "",
  first_name: "",
  last_name: "",
  phone: "",
  zip_code: "",
};

export default function (state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case REGISTER_SUCCESS:
      return {
        ...state,
        isAuthenticated: false
      };
    case REGISTER_FAIL:
      return state;
    default:
      return state;
  }
}

src/views/auth/signUp/index.js

import React, { useState } from "react";
import { Redirect } from "react-router-dom";
import {
  Button,
  Flex,
  FormControl,
  FormLabel,
  Input,
  InputGroup,
  Text,
} from "@chakra-ui/react";
import DefaultAuth from "layouts/auth/Default";
import CSRFToken from "components/csrfToken/csrfToken";
import illustration from "assets/img/auth/auth.png";
import { register } from "actions/auth";
import { connect } from "react-redux";

function Register({ register }) {
  const [formData, setFormData] = useState({
    username: "",
    password: "",
    re_password: "",
  });
  const [userCreated, setUserCreated] = useState(false);
  const [showPassword, setShowPassword] = React.useState(false);
  const [showRePassword, setShowRePassword] = React.useState(false);

  const { username, password, re_password } = formData;

  const onChange = (e) =>
    setFormData({
      ...formData,
      [e.target.name]: e.target.value,
    });

  const onSubmit = (e) => {
    e.preventDefault();

    if (password === re_password) {
      register(username, password, re_password);
      setUserCreated(true);
    }
  };

  if (userCreated) {
    return <Redirect to="/" />;
  }

  return (
    <DefaultAuth illustrationBackground={illustration} image={illustration}>
      <Flex>
        <Flex>
          <form onSubmit={(e) => onSubmit(e)}>
            <CSRFToken />
            <FormControl>
              <FormLabel>
                Username<Text>*</Text>
              </FormLabel>
              <Input
                onChange={(e) => onChange(e)}
                defaultValue={username}
              />
              <FormLabel>
                Password<Text>*</Text>
              </FormLabel>
              <InputGroup>
                <Input
                  variant="auth"
                  onChange={(e) => onChange(e)}
                  defaultValue={password}
                />
              </InputGroup>
              <FormLabel>
                Repeat Password<Text>*</Text>
              </FormLabel>
              <InputGroup>
                <Input
                  variant="auth"
                  onChange={(e) => onChange(e)}
                  defaultValue={re_password}
                />
              </InputGroup>
              <Button type="submit">
                Create User
              </Button>
            </FormControl>
          </form>
        </Flex>
      </Flex>
    </DefaultAuth>
  );
}

export default connect(null, { register })(Register);
reactjs django django-rest-framework csrf django-cors-headers
© www.soinside.com 2019 - 2024. All rights reserved.