通过Cypress.io以编程方式登录到Django服务器(不使用UI) [英] Logging into a Django server with Cypress.io programmatically (without using UI)

查看:55
本文介绍了通过Cypress.io以编程方式登录到Django服务器(不使用UI)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

必须遗漏一些明显的东西,但是由于其CSRF保护,我在登录Django时非常受困扰。



我看着



而且,通过我的代码,我永远不会传递使Django返回403错误的csrf令牌。

  Cypress.Commands .add( login,(用户名,密码)=> {
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');
//调试器;

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

cy.request({
方法:'POST',
格式:true,
url:login_url,
//正文:{'username':'guest','password':'password','csrfmiddlewaretoken': cy.getCookie('csrftoken')。value}
正文:{'username':'guest','password':'password','csrfmiddlewaretoken':hidden_​​token}
})
})



赛普拉斯的错误:



< a href = https://i.stack.imgur.com/PgQgj.png rel = nofollow noreferrer>



我怀疑POST数据与令牌未定义有关联通过隐藏形式输入或cookie获取方法,如 console.log 所示。



现在,我已经开始查看 https://github.com/cypress-io/cypress-example-recipes/tree/master/examples / logging-in__csrf-tokens ,我想我应该能够调整策略#1:从HTML解析令牌以选择 $( input [name = 'csrfmiddlewaretoken'])。value ,但我希望有人以前曾经这样做过。



我的另一个想法是有条件地添加一个向Django请求中间件,该中间件将从请求标头中获取csrftoken,并在缺少时将其注入POST表单数据中。假如我将其插入CSRF内容之前可以触发,那行得通吗?



最后,我打算排除 sessionid 重置令牌,以便我仅登录一次即可运行多个测试。



env:Django 1.10,cypress 1.4.2,现在已升级到2.0.0,相同的问题。

解决方案

您可以使用<$获得登录所需的第一个CSRF令牌c $ c> HEAD 请求并查看cookie(无需解析页面)。



此外,您还可以自定义 cy.login()返回令牌(异步,因此您需要使用 .then()),而不必调用如果以后需要POST请求令牌,则再次 cy.getCookie('csrftoken')

  Cypress.Commands.add('login',(用户名,密码)=> {

return cy.request({
网址: / login /,
方法: HEA D’// Cookie位于HTTP标头中,因此HEAD足以满足
})。then(()=> {

cy.getCookie('sessionid')。should('not.exist')
cy.getCookie('csrftoken')。its('value')。then((token )=> {
let oldToken =令牌
cy.request({
url:'/ login /',
方法:'POST',
形式: true,
followRedirect:false,//登录后无需检索页面
正文:{
用户名:用户名,
密码:密码,
csrfmiddlewaretoken:令牌
}
})。then(()=> {

cy.getCookie('sessionid')。should('exist')
return cy。 getCookie('csrftoken')。its('value')

})
})
})

})

注意:令牌在登录后会更改,因此有两个 cy.getCookie('csrftoken')调用。



之后,您可以在测试中按以下方式使用它(请参阅 https://docs.djangoproject.com/en/3.0/ref/csrf/ 了解为何需要标头):

  cy.login()。then((csrfToken)=> {

cy.request({
method:'POST',
url:'/ api / baz /',
body:{'foo':' bar'},
标头:{'X-CSRFToken':csrfToken}
})

})


Must be missing something obvious but I am very much stuck on logins into Django due to its CSRF protection.

I looked Check out our example recipes using cy.getCookie() to test logging in using HTML web forms but that really doesn't help that much if the first thing it recommends is disabling CSRF.

What Django wants:

This is what a normal, CSRF-protected, Django login view is expecting in its incoming POST data:

csrfmiddlewaretoken=Y5WscShtwZn3e1eCyahdqPURbfHczLyXfyPRsEOWacdUcGNYUn2EK6pWyicTLSXT
username=guest
password=password
next

It is not looking for the CSRF in the request headers and it is not setting x-csrf-token on the response headers.

And, with my code, I am never passing in the csrf token which gets Django to return a 403 error.

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}
    })
})

Cypress's error:

I suspect that the POST data has something to do with the token being undefined via the both the hidden form input or the cookie acquisition approach, as shown by the console.log for either.

Now, I've already started looking at https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/logging-in__csrf-tokens and I think I should be able to adjust strategy #1: parse token from HTML to pick up $("input[name='csrfmiddlewaretoken']").value but I was hoping someone had done this before.

One other idea I have is to conditionally add a request Middleware to Django that would grab the csrftoken from the request headers and inject into the POST form data when it's missing. Provided I insert it to fire before the CSRF stuff, would that work?

Last, I was planning to exclude the sessionid token from getting reset so that I can run multiple tests after logging in just once.

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

解决方案

You can get the first CSRF token required for login using a HEAD request and looking at the cookies (no need to parse the page).

Also you can have your custom cy.login() return the token (asynchronously, so you need to use .then()) instead of having to call cy.getCookie('csrftoken') again if you need a token afterwards for POST requests and such:

Cypress.Commands.add('login', (username, password) => {

  return cy.request({
    url: '/login/',
    method: 'HEAD' // cookies are in the HTTP headers, so HEAD suffices
  }).then(() => {

    cy.getCookie('sessionid').should('not.exist')
    cy.getCookie('csrftoken').its('value').then((token) => {
      let oldToken = token
      cy.request({
        url: '/login/',
        method: 'POST',
        form: true,
        followRedirect: false, // no need to retrieve the page after login
        body: {
          username: username,
          password: password,
          csrfmiddlewaretoken: token
        }
      }).then(() => {

        cy.getCookie('sessionid').should('exist')
        return cy.getCookie('csrftoken').its('value')

      })
    })
  })

})

Note: The token changes after login, therefore two cy.getCookie('csrftoken') calls.

Afterwards you can just use it in the following way in your tests (see https://docs.djangoproject.com/en/3.0/ref/csrf/ for why the header is needed):

cy.login().then((csrfToken) => {

  cy.request({
    method: 'POST',
    url: '/api/baz/',
    body: { 'foo': 'bar' },
    headers: { 'X-CSRFToken': csrfToken }
  })

})

这篇关于通过Cypress.io以编程方式登录到Django服务器(不使用UI)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆