首页 文章

使用Cypress.io登录Django服务器

提问于
浏览
3

一定是缺少明显的东西,但由于其CSRF保护,我非常坚持登录Django .

我看了Check out our example recipes using cy.getCookie() to test logging in using HTML web forms但如果它推荐的第一件事就是禁用CSRF,那真的没那么大 .

Django想要什么:

这是正常的,受CSRF保护的Django登录视图在其传入的POST数据中所期望的:

csrfmiddlewaretoken=Y5WscShtwZn3e1eCyahdqPURbfHczLyXfyPRsEOWacdUcGNYUn2EK6pWyicTLSXT
username=guest
password=password
next

它不在请求标头中查找CSRF,也没有在响应标头上设置 x-csrf-token .

enter image description here

并且,使用我的代码,我永远不会传递使用Django返回403错误的csrf令牌 .

Cypress.Commands.add("login", (username, password) => {
    var login_url = Cypress.env("login_url");

    cy.visit(login_url)

    var hidden_token = cy.get("input[name='csrfmiddlewaretoken']").value;
    console.log(`hidden_token:${hidden_token}:`)

    console.log(`visited:${login_url}`)
    var cookie = cy.getCookie('csrftoken');
    // debugger;

    var csrftoken = cy.getCookie('csrftoken').value;
    console.log(`csrftoken:${csrftoken}:`) 
    console.log(`request.POST`)

    cy.request({
        method: 'POST',
        form: true,
        url: login_url,
        // body: {'username': 'guest', 'password': 'password', 'csrfmiddlewaretoken': cy.getCookie('csrftoken').value}
        body: {'username': 'guest', 'password': 'password', 'csrfmiddlewaretoken': hidden_token}
    })
})

赛普拉斯的错误:

enter image description here

我怀疑POST数据通过隐藏表单输入或cookie获取方法与令牌 undefined 有关,如 console.log 所示 .

现在,我已经开始关注https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/logging-in__csrf-tokens并且我认为我应该能够调整 strategy #1: parse token from HTML 来接收 $("input[name='csrfmiddlewaretoken']").value 但我希望之前有人这样做过 .

我的另一个想法是有条件地向Django添加一个请求中间件,它将从请求头中获取csrftoken,并在丢失时注入POST表单数据 . 如果我在CSRF之前将其插入火中,那会起作用吗?

最后,我计划将 sessionid 令牌排除在重置之外,这样我只需登录一次即可运行多个测试 .

env: Django 1.10, cypress 1.4.2, now upgraded to 2.0.0, same issue.

2 回答

  • 2

    赛普拉斯自动发送带有请求的名为“csrftoken”的cookie,但Django希望将csrf令牌称为“csrfmiddlewaretoken” . 因此,我必须获取令牌并手动传递,如下所示:

    cy.getCookie('csrftoken')
        .then((csrftoken) => {
            cy.request({
                method: 'POST',
                url: your_url_here,
                // "form: true" is required here for the submitted information to be accessible via request.POST in Django (even though the docs make it sound like a bare 'POST' request can be made without the "form: true")
                form: true,
                body: {
                    csrfmiddlewaretoken: csrftoken.value,
                    testing: true,
                    obj_model: 'Customer',
                    field_name: 'name',
                    field_value: 'Customer - Testing'
                }
            })
            .then((result) => {
                expect(result.body.success).to.equal(true)
            })
            .then(() => {
                //additional processing here if needed
            })
        })
    
  • 0

    你是对的,赛普拉斯没有在体内发送令牌,因为它是 undefined ,因为你在 input 上使用 .get() 来获取令牌 .

    您正在使用 .get() 作为同步调用,但它实际上是 async . 这是因为赛普拉斯将智能地重试找到DOM元素,这需要不确定的时间 . 这是赛普拉斯的核心概念,可实现内置测试 . 赛普拉斯的文档详细说明了这一点,所以请在这里查看:https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Default-Assertions

    在您的情况下,如何访问DOM中元素的属性应该放在回调中:

    cy.get("input[name='csrfmiddlewaretoken']").then($input=>{
        const hidden_token = $input.val()
        cy.request({
            method: 'POST',
            form: true,
            url: login_url,
            // body: {'username': 'guest', 'password': 'password', 'csrfmiddlewaretoken': cy.getCookie('csrftoken').value}
            body: {'username': 'guest', 'password': 'password', 'csrfmiddlewaretoken': hidden_token}
        })
    })
    

    ...

    Pro-tip: using Cypress's doc search will usually lend you what you need
    enter image description here

相关问题