reactjs - Django Rest Framework 无法识别使用 Axios 从 React 应用程序发送的 CSRF cookie
问题描述
我做了很多年的后端开发人员,但现在我也想学习前端,所以我选择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);
})
}
这对我有用。