簡體   English   中英

Django Rest Framework無法識別使用Axios從React應用發送的CSRF cookie

[英]Django Rest Framework doesn't recognize CSRF cookie sent from a a React app using Axios

我已經擔任后端開發人員很多年了,但是現在我也想學習前端,因此我選擇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.)

以我的方式獲取令牌然后以嘗試的方式使用令牌是否正確?

我發現的唯一解決方案是使登錄過程免於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);
    })
  }

這對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM