【问题标题】:Django Rest Framework doesn't recognize CSRF cookie sent from a a React app using AxiosDjango Rest Framework 无法识别从使用 Axios 的 React 应用程序发送的 CSRF cookie
【发布时间】:2019-01-10 23:44:30
【问题描述】:

我从事后端开发多年,但现在我也想学习前端,所以我选择 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.)

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

【问题讨论】:

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


    【解决方案1】:

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

    我创建了一个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);
        })
      }
    

    这对我有用。

    【讨论】:

      猜你喜欢
      • 2019-06-03
      • 2021-08-31
      • 1970-01-01
      • 2023-04-09
      • 2022-11-05
      • 2013-05-12
      • 2017-12-06
      • 2017-01-08
      • 2021-04-07
      相关资源
      最近更新 更多