Django Rest Framework无法识别使用Axios从React应用发送的CSRF cookie

时间:2019-01-08 20:39:50

标签: reactjs django-rest-framework axios csrf django-csrf

我多年来一直是后端开发人员,但是现在我也想学习前端,因此我选择 React 作为我的前端框架。我花了两天时间学习使用 Axios React 应用程序向 Django Rest Framework 后端发送请求的过程,而我与<强烈的> csrf cookie 问题。到目前为止,我已经发布了几个问题,最后,我可以发送一个正确的格式请求,该请求被后端接受了……只是得到了Forbidden (CSRF token missing or incorrect.)错误。

我想我获取和使用 csrf令牌的方法可能不正确,因此,我感谢您指出我的错误并教我解决方法。

首先,我向后端发送一个GET请求,其唯一目的是获得 csrf令牌(我这样做),然后将cookie设置为此类令牌:

class App extends Component {
  render() {
    const axios = require('axios');
    axios.get('http://127.0.0.1:8000/es/api/hand_shake/')
    .then(function (response) {
      Cookies.set('csrftoken', response['data']['cookie']);
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })

    return (
      <div className="App">
        <LoginModal />
      </div>
    );
  }
}

export default App;

第二,在另一个模块中,我从cookie中获取令牌,并在POST请求中使用它:

handleClick() {
    const axios = require('axios');
    var csrfCookie = Cookies.get('csrftoken');
    console.log(csrfCookie)
    axios.post('http://127.0.0.1:8000/es/api-auth/login/',
      {
        next: '/',
        username: 'admin@admin.com',
        password: 'Cancun10!',
      },
      {
        headers: {
          'x-xsrf-token': csrfCookie,
        },
        withCredentials: true,
      }
    )
    .then(function (response) {
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })
  }

最后,我有后端接受请求,但是出现错误Forbidden (CSRF token missing or incorrect.)

以正确的方式获取令牌,然后以尝试的方式使用令牌是否正确?

1 个答案:

答案 0 :(得分:0)

我发现的唯一解决方案是使登录过程免于csrf验证,但我不得不放弃 Django Rest Framework 的默认身份验证功能(如果有人知道如何使用 DRF < / strong>默认身份验证,请分享)并实现我自己的自定义身份验证视图。

我创建了一个ViewSet并用csrf_exempt装饰,如下所示:

from django.views.decorators.csrf import csrf_exempt

class LoginViewSet(viewsets.ViewSet):
    permission_classes = ()

    @csrf_exempt
    def post(self, request):
        from PhotosManagerApp.email_backend import EmailBackend

        email_backend_instance = EmailBackend()
        user = email_backend_instance.authenticate(request, username=request.data['username'], password=request.data['password'])
        if user:
            try:
                usr_token = Token.objects.get(user=user)
            except:
                usr_token = None
        else:
            usr_token = None

        return Response({'token': str(usr_token)})

您还必须在urls.py中装饰视图:

path('login/', csrf_exempt(views.LoginViewSet.as_view({'post': 'post'}))),

在找到正确的配置之前,我在使用 Django settings.py时遇到了很多麻烦:

from corsheaders.defaults import default_headers

CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_HEADERS = default_headers + (
    'xsrfheadername',
    'xsrfcookiename',
    'content-type',
    'x-csrftoken',
)

CORS_ORIGIN_ALLOW_ALL = True
CSRF_COOKIE_NAME = "csrftoken"

我遇到很多麻烦,直到发现必须在default_headers上加上CORS_ALLOW_HEADERS

现在,只需确保使用withCredentials = false发送请求:

handleClick() {
    const axios = require('axios');
    //axios.defaults.withCredentials = true;
    axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
    axios.defaults.xsrfCookieName = "csrftoken";
    axios.post('http://127.0.0.1:8000/es/api/login/',
      {
        username: 'admin@admin.com',
      },
    )
    .then(function (response) {
      Cookies.set('token', "Token ".concat(response.data.token), {"expires": 10})
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    })
  }

这对我有用。