[英]Django Rest Framework doesn't recognize CSRF cookie sent from a a React app using Axios
I have been a backend developer for many years, but now I want to learn frontend also, so I choose React as my frontend framework to start. 我已经担任后端开发人员很多年了,但是现在我也想学习前端,因此我选择React作为我的前端框架。 I have expended two days learning to send requests from a React app using Axios to a Django Rest Framework backend, and I have clashed with that csrf cookie issue.
我已经花了两天的时间来学习如何使用Axios将来自React应用的请求发送到Django Rest Framework后端,并且已经遇到了csrf cookie问题。 I have posted several questions so far, and I could, finally, been able to send a right formed request that is accepted by the backend...only to get a
Forbidden (CSRF token missing or incorrect.)
error. 到目前为止,我已经发布了几个问题,最后,我可以发送一个正确的格式请求,该请求被后端接受了……只是得到了一个
Forbidden (CSRF token missing or incorrect.)
错误。
I guess my approach to get and use the csrf token might not be the right one, so I would appreciate you to point my mistake and teach me to solve it. 我想我获取和使用csrf令牌的方法可能不正确,因此,我感谢您指出我的错误并教我解决方法。
First, I send a GET
request to the backend with the only goal of getting a csrf token (which I do), and set a cookie to such token: 首先,我向后端发送
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;
Second, in another module, I get the token from the cookie and use it in a POST
request: 其次,在另一个模块中,我从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);
})
}
I have, finally, got the backend to accept the request, but I get the error Forbidden (CSRF token missing or incorrect.)
. 最后,我有后端可以接受请求,但是却收到错误信息
Forbidden (CSRF token missing or incorrect.)
。
Is it right to get the token the way I am doing it, and then to use it the way I am attempting? 以我的方式获取令牌然后以尝试的方式使用令牌是否正确?
The only solution I found was to exempt login process from csrf validation, but I had to give up Django Rest Framework default authentication functionality (if anybody knows how to do it with DRF default authentication, please share) and implement my own custom authentication view. 我发现的唯一解决方案是使登录过程免于csrf验证,但是我不得不放弃Django Rest Framework默认身份验证功能(如果有人知道如何使用DRF默认身份验证,请分享),并实现我自己的自定义身份验证视图。
I created a ViewSet
and decorated it with csrf_exempt
, like this: 我创建了一个
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)})
You also have to decorate your view in urls.py
: 您还必须在
urls.py
装饰视图:
path('login/', csrf_exempt(views.LoginViewSet.as_view({'post': 'post'}))),
I had many troubles with Django settings.py
, until I found the right configuration: 在找到正确的配置之前,我对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"
I had many troubles until I found that I had to add default_headers
to CORS_ALLOW_HEADERS
. 我遇到很多麻烦,直到发现必须将
default_headers
添加到CORS_ALLOW_HEADERS
。
Now, just ensure to send your request with withCredentials = false
: 现在,只需确保使用
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);
})
}
This is what worked for me. 这对我有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.