问题描述
我使用 Vuejs 作为前端,使用 Django rest 框架作为后端,我对如何使用 csrf 令牌有些困惑,我的问题有两部分,首先我写下我的配置。
首先如 Django documentation 所述,“如果您的视图未呈现包含 csrf_token
模板标记的模板,Django 可能不会设置 CSRF 令牌 cookie。这在表单被动态添加到页面的情况下很常见。为了解决这种情况,Django 提供了一个视图装饰器来强制设置 cookie:ensure_csrf_cookie()
",所以这是我的视图,用于呈现加载 webpack 包的页面。
@ensure_csrf_cookie
def main_view(request):
return render(request,'index.html')
再次作为 Django 文档,我使用以下配置将 csrf 令牌与 Axios 请求一起发送。
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0,name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
//axios request
async createFromCSV(token,data) {
const options = {
headers: {
Authorization: `Bearer ${token}`,"Content-Type": "application/json;charset=UTF-8","X-CSrftoken": data.headers["csrftoken"]
}
// "Access-Control-Allow-Origin": "*",};
return await axios.post(`${CREATE_FROM_CSV}`,data.data_,options);
}
最后这是应该处理发布请求的视图(我省略了任何相关代码)
@requires_csrf_token
@api_view(['POST'])
@c_login_required()
def create_from_csv(request):
if 'data_' in request.data:
return JsonResponse({})
else:
raise MyValidationError({
'message': 'اطلاعات ورودی درست نیست!!'
})
所以这是我的问题:
1-第一个问题是无论csrftoken的值是多少,或者即使csrftoken标头存在与否,请求都可以通过而没有任何错误,我什至使用邮递员进行双重检查并发送没有任何csrf令牌标头的请求,但没有得到任何错误,为什么 @requires_csrf_token
不起作用?
2- 如上所述,我使用 Django 文档指南从 html 页面获取令牌,当我检查请求时,我注意到另一个 cookie In request 每次它的值与我手动检索的令牌完全相同,这个 csrftoken 如何已经自动设置了吗?
解决方法
我找到了答案,我搜索了很多,但我找不到合适的地方描述在 Django rest 框架中使用 csrf 与 react 和 vuejs 等单页应用程序集成,所以我先回答我的问题,然后写下来整个配置。
我问题的第一部分的答案是您应该使用 @csrf_protect
装饰器而不是 @requires_csrf_token
因为即使 @requires_csrf_token
的工作方式与 csrf_protect 类似,但从不拒绝传入的请求。
虽然我解决了这个问题,但我的请求在没有任何 csrf 令牌的情况下处理,还有另一个问题,它是 DRF documentation stated,“REST 框架中的 CSRF 验证与标准 Django 的工作方式略有不同,因为需要同时支持会话和非- 对相同视图的基于会话的身份验证。这意味着只有经过身份验证的请求需要 CSRF 令牌,匿名请求可以在没有 CSRF 令牌的情况下发送。这种行为不适合登录视图,它应该始终应用 CSRF 验证”,因此匿名请求不需要 csrf 令牌,我所要做的就是将 @api_view
装饰器放在 @csrf_protect
上方以首先对用户进行身份验证并解决此问题。
@api_view(['POST'])
@csrf_protect
@c_login_required()
def create_from_csv(request):
if 'data_' in request.data:
return JsonResponse({})
else:
raise MyValidationError({
'message': 'اطلاعات ورودی درست نیست!!'
})
对于我的问题的第二部分,您只需按上述方式检索令牌,然后在请求标头 "X-CSRFToken": yourcsrftoken
总结:
1- 在呈现请求来自的页面的视图上使用 @ensure_csrf_cookie
,此装饰器强制视图发送 csrf cookie。
2- 如上所述检索令牌,并使用此密钥在请求标头中的 post 请求中发送令牌:X-CSRFToken
.
3- 在对用户进行身份验证后处理发布请求的视图上使用 @csrf_protect
,因为在 Django 休息框架中匿名用户不需要令牌