如何使用 Django webpack loader 在与 vuejs 集成的 Django 中使用 csrf 令牌?

问题描述

我使用 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 休息框架中匿名用户不需要令牌