【问题标题】:Why DRF shows Forbidden (CSRF cookie not set.) without @api_view(['POST'])?为什么 DRF 在没有 @api_view(['POST']) 的情况下显示 Forbidden (CSRF cookie not set.)?
【发布时间】:2022-01-26 18:50:22
【问题描述】:

我正在学习 react 并尝试使用 django-rest-framework(backend) 和 react(frontend) 制作登录表单。在反应中,我创建了一个登录表单,当我提交表单时,它会将 axios.post 发送到我的视图函数。问题是 django 报错和消息:Forbidden (CSRF cookie not set.)

Obs1:如果我包含 de @api_view(['POST']) 装饰器有效,但我想知道是否可以在没有它的情况下发出请求。

Obs2:当我的反应表单渲染时,一个创建 csrf_token 的函数被调用,所以 csrf_token 被发送但 django 没有读取它

Obs3:我的 django 在 http://127.0.0.1:8000/,我的 reactapp 在 http://192.168.56.1:3000.

当我的登录呈现时:

useEffect(()=>{
    axios({method:'get', url:'http://127.0.0.1:8000/usuario/gera})
    .then(response=>{
        setToken(response.data)
    })
    .catch(error=>{})
},[])

表单提交时:

function logar(e){
    document.cookie = `X-CSRFToken=${token}`
    login(email, senha1)
    e.preventDefault()
}

我的axios(内部登录功能):

let token = getCookie('X-CSRFToken');

axios({
    method:'post', 
    url: url, 
    data:{email:email, password1:senha},
    headers: {'X-CSRFTOKEN': token},
    withCredentials: true
})
.then((response)=>{
    console.log(`Reposta: ${response.data}`)
})
.catch((error)=>{
    console.log(`Erro: ${error.data}`)
});

我的 Django 视图:

def login_usuario(request):
    if request.method == 'POST':
        return HttpResponse('Something')

我的 Django 设置:

CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN'

CSRF_COOKIE_NAME = 'X-CSRFTOKEN'

CORS_ALLOW_HEADERS = [
    'X-CSRFTOKEN',
    'csrftoken',
    'X-XSRF-TOKEN',
    'content-type',
    'x-requested-with',
    'Authorization',
    'Set-Cookie'
]

CORS_ALLOW_CREDENTIALS = True

CSRF_TRUSTED_ORIGINS = ['http://localhost:3000']

CSRF_COOKIE_DOMAIN = 'http://192.168.56.1:3000' 

CSRF_COOKIE_PATH = 'http://localhost:3000'

SESSION_COOKIE_DOMAIN = 'http://localhost:3000'

【问题讨论】:

  • 这通常是客户端的问题。你确定token 是正确的吗?转到 Chrome 开发人员工具(或您选择的浏览器中的等效工具)中的“网络”标签。当您执行此 axios 帖子时,应该会显示此请求。检查请求是否具有正确的 X-CSRFTOKEN 标头。
  • Http 标头不区分大小写。它是否大写都没有关系。但是有可能 Django 被配置为使用与默认“X-CSRFToken”不同的标头名称。 docs.djangoproject.com/en/4.0/ref/settings/…
  • 对不起,我的第一个问题。我会提供更多细节!
  • 您似乎更改了 Django 中的许多默认 CSRF 配置。大概你对每一个都有一些理由。为 django 应用程序和 javascript 包使用不同的主机会使从 cookie 中读取 csrf 令牌变得更加困难,因为浏览器会阻止 javascript 访问某些数据。这就是存在跨站点请求伪造保护的原因。
  • 我做了这个改变,因为没有任何效果 kkkkk。我认为不同的主机是问题,但我需要有人告诉我确定。谢谢!!

标签: reactjs django django-rest-framework axios


【解决方案1】:

您可能没有在 axios http 请求中包含正确的 CSRF 令牌。

如果你告诉 Axios 标头名称和 cookie 名称,它应该能够添加正确的标头和令牌。如果您使用 Django 的默认 CSFR 配置,这些值应该可以工作。

axios({
    method:'post', 
    url: url, 
    data:{email:email, password1:senha},
    xsrfCookieName: 'csrftoken',
    xsrfHeaderName: 'X-CSRFTOKEN',
    withCredentials: true
})

为确保 Django 已设置 csrf 令牌,您可以在视图函数上使用 ensure_csrf_token 装饰器,为您的 react 应用提供页面。

from django.views.decorators.csrf import ensure_csrf_token

@ensure_csrf_token
def react_app_view(request):
    return render(request, "react-app.html")

您可以使用浏览器 javascript 控制台检查 cookie 是否已设置。

> document.cookie
'csrftoken=G2fjig7PImjIcvUFa6o39fTxwRcovp6Zh5iC5pkcmhBRETliwrZ2jt6bbcrvtpKa'

【讨论】:

    猜你喜欢
    • 2019-06-16
    • 2022-01-12
    • 2019-03-16
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    相关资源
    最近更新 更多