Cypress + 2 个超级域 + AntiforgeryToken = Cypress 无法重定向

Cypress + 2 Super Domains + AntiforgeryToken = Cypress can't be redirect

我目前正在设置一个 Cypress 解决方案来测试基于 Nuxt 和 .NET 的产品。该产品使用基于 SSO 的登录页面,该页面具有与该产品不同的超级域。

这会导致 cookie 出现问题。实际上,对产品的访问会生成到 SSO 身份验证页面的重定向。并且,在验证身份验证表单之后,由 Cypress 驱动的 Chrome 进入了一个调用循环,其中 cookie 的属性存在错误,特别是 SameSite 属性的值与预期的 SSO 端相比是不正确的。

目前,浏览器中有几个功能被禁用,即:

摘自 cypress/plugins/index.js

  on('before:browser:launch', (browser = {}, launchOptions) => {
    if (browser.family === 'chromium') {
      launchOptions.args.push(
        "--disable-features=SameSiteByDefaultCookies,CrossSiteDocumentBlockingIfIsolating,CrossSiteDocumentBlockingIfIsolating,IsolateOrigins,site-per-process"
      );
    }
    console.log(launchOptions.args);
    return launchOptions
  });

即使禁用 SSO 上的所有保护,也无法使 Cypress 正常工作。

Here is an Excel file 以及通过 Chrome 控制台列出的所有 HTML 请求。该文件描述了 Cypress 驱动的 Chrome 与“经典”Chrome.

之间的差异

注意:在赛普拉斯的配置中添加 "chromeWebSecurity": false, 不会改变任何东西

不完全了解潜在的问题是什么,我无法很好地描述问题。针对各种论坛(包括 Whosebug)上公开的类似问题提出的所有解决方案都不足以解决我的问题。你能帮帮我吗?

提前致谢。

此致, 亚历山大.

这可能是由 10 月 21 日发布的 chrome 94 更新引起的。更新 94 删除了 SameSiteByDefaultCookies 标志,因此修复不再有效。

如果您遇到与我相同的问题,我通过拦截所有请求、检查它们是否具有 set-cookie header(s) 并重写 SameSite 属性来解决它。可能有一种更简洁的方法来做到这一点,因为这确实会使赛普拉斯仪表板有点混乱。您可以将其添加为命令以便于重复使用:

在您的命令文件中:

declare namespace Cypress {
  interface Chainable<Subject> {
    disableSameSiteCookieRestrictions(): void;
  }
}

Cypress.Commands.add('disableSameSiteCookieRestrictions', () => {
  cy.intercept('*', (req) => {
    req.on('response', (res) => {
      if (!res.headers['set-cookie']) {
        return;
      }

      const disableSameSite = (headerContent: string): string => {
        return headerContent.replace(/samesite=(lax|strict)/ig, 'samesite=none');
      }

      if (Array.isArray(res.headers['set-cookie'])) {
        res.headers['set-cookie'] = res.headers['set-cookie'].map(disableSameSite);
      } else {
        res.headers['set-cookie'] = disableSameSite(res.headers['set-cookie']);
      }
    })
  });
});

用法:

  it('should login using third party idp', () => {
    cy.disableSameSiteCookieRestrictions();
    //add test body here
  });

或者,运行 它在每次测试之前:

  beforeEach(() => cy.disableSameSiteCookieRestrictions());

我终于找到了这个 SSO 身份验证的解决方案。

代码如下:

Cypress.Commands.add('authentificationSSO', (typedeCompte, login) => {
  let loginCompte = 'login';
  let motDePasseCompte = 'password';
  
  let baseUrlSSO = Cypress.env('baseUrlSSO') ? Cypress.env('baseUrlSSO') : '';
  let baseUrl = Cypress.config('baseUrl') ? Cypress.config('baseUrl') : '';

  cy.request(
    'GET',
    baseUrlSSO +
      '/Account/Login?${someParameters}%26redirect_uri%3D' +
      baseUrl
  ).then((response) => {
    let requestVerificationToken = '0';
    let attributsCookieGroupe = [];
    let nomCookie = '';
    let tokenCookie = '';
    const documentHTML = document.createElement('html');
    documentHTML.innerHTML = response.body;
    attributsCookieGroupe = response.headers['set-cookie'][0].split(';');

    const loginForm = documentHTML.getElementsByTagName('form')[0];
    const token = loginForm.querySelector('input[name="__RequestVerificationToken"]')?.getAttribute('value');

    requestVerificationToken = token ? token : '';
    nomCookie = attributsCookieGroupe[0].split('=')[0];
    tokenCookie = attributsCookieGroupe[0].split('=')[1];

    cy.setCookie(nomCookie, tokenCookie, { sameSite: 'strict' });

    cy.request({
      method: 'POST',
      url:
        baseUrlSSO +
        '/Account/Login?{someParameters}%26redirect_uri%3D' +
        baseUrl,
      followRedirect: false,
      form: true,
      body: {
        Login: loginCompte,
        Password: motDePasseCompte,
        __RequestVerificationToken: requestVerificationToken,
        RememberLogin: false
      }
    });
  });
});