有没有办法使用 cypress/JS 以编程方式通过 Keycloak 登录应用程序?

Posted

技术标签:

【中文标题】有没有办法使用 cypress/JS 以编程方式通过 Keycloak 登录应用程序?【英文标题】:Is there a way to login into the application through Keycloak programmatically using cypress/JS? 【发布时间】:2021-07-10 04:27:13 【问题描述】:

我在 Cypress 中为受 Keycloak 保护的 Web 应用程序编写自动化测试。我已经设法从 keycloak 中检索 jwt 令牌,但我不知道如何处理它。我已经看到,在您登录 keycloak 后,您会被重定向到您的域,并且 keyclock 会设置 cookie、本地存储等。 当您登录他们的页面时,有没有办法以编程方式获得与 keyclock 相同的结果?换句话说,有类似的东西:

cy.getToken().then((token) => 
   cy.login(token);
   cy.visit(myDomain)
)

【问题讨论】:

【参考方案1】:

您可以使用插件cypress-keycloak 来实现。

安装后转到cypress/support/commands.js并写:

// Using ES6
import 'cypress-keycloak';

OR

// using CommonJS
require('cypress-keycloak');

然后在您的测试中您可以编写(示例取自 cypress-keycloak npm 页面):

describe('thing', () => 
  beforeEach(() => 
    cy.login(
      root: 'https://keycloak.babangsund.com',
      realm: 'stage',
      username: 'babangsund',
      password: 'bacon',
      client_id: 'frontend',
      redirect_uri: 'https://babangsund.com/',
    );

    // or login with OTP
    cy.loginOTP(
      root: 'https://keycloak.babangsund.com',
      realm: 'stage',
      username: 'babangsund',
      password: 'bacon',
      client_id: 'frontend',
      redirect_uri: 'https://babangsund.com/',
      otp_secret: 'OZLDC2HZKM3QUC...', // e.g. 32 chars
      otp_credential_id: '5e231f20-8ca7-35e1-20a694b60181ca9', // e.g. 36 chars
    );
  );

  afterEach(() => 
    cy.logout(
      root: 'https://keycloak.babangsund.com',
      realm: 'stage',
      redirect_uri: 'https://babangsund.com/',
    );
  );
);

【讨论】:

感谢您的回答,但对我来说,它似乎不起作用。我之前尝试过其他一些插件,但没有运气。你试过这个插件并且它对你有用吗? ` 您是否正确输入了所有值,如root、realm、用户名、密码等?还有你安装插件后在cypress/support/commands.js下添加了require('cypress-keycloak');吗? 是的,我已经完成了他们网站上所说的一切。【参考方案2】:

看看库,cypress-keycloak-commands 是另一个更受欢迎的库(大约是每周下载量的三倍)。

我喜欢它基于配置的方式,并且有 cy.kcFakeLogin() 用于基于夹具的模拟。

如果你想了解Keycloak的详细信息,还有这个博客Cypress.io Keycloak Integration。

如果链接消失,转载以备日后参考

Cypress.Commands.add('kcLogin', (username, password) => 
  const kcRoot = 'http://my.keycloak.com';
  const kcRealm = 'MYrealm';
  const kcClient = 'my-client';
  const kcRedirectUri = 'http://localhost:3000/';
  const loginPageRequest = 
    url: `$kcRoot/auth/realms/$kcRealm/protocol/openid-connect/auth`,
    qs: 
      client_id: kcClient,
      redirect_uri: kcRedirectUri,
      state: createUUID(),
      nonce: createUUID(),
      response_mode: 'fragment',
      response_type: 'code',
      scope: 'openid'
    
  ;
  // Open the KC login page, fill in the form with username and password and submit.
  return cy.request(loginPageRequest)
    .then(submitLoginForm);
  ////////////
  function submitLoginForm(response) 
    const _el = document.createElement('html');
    _el.innerHTML = response.body;
    // This should be more strict depending on your login page template.
    const loginForm = _el.getElementsByTagName('form');
    const isAlreadyLoggedIn = !loginForm.length;
    if (isAlreadyLoggedIn) 
      return;
    
    return cy.request(
      form: true,
      method: 'POST',
      url: loginForm[0].action,
      followRedirect: false,
      body: 
        username: username,
        password: password        
      
    );
  
  // Copy-pasted code from KC javascript client. It probably doesn't need to be 
  // this complicated but I refused to spend time on figuring that out.
  function createUUID() 
    var s = [];
    var hexDigits = '0123456789abcdef';
    for (var i = 0; i < 36; i++) 
      s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    
    s[14] = '4';
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
    s[8] = s[13] = s[18] = s[23] = '-';
    var uuid = s.join('');
    return uuid;
  
);

【讨论】:

我也试过这个插件,但没有成功。它只是没有让我登录。你还需要编辑这个代码,“const loginForm = _el.getElementsByTagName('form');”这不起作用。我不得不以另一种方式从这个表单中获取 url。谢谢你的回答。 哦,顺便说一句,here 是getElementsByTagName(),它应该内置在您的浏览器中。 实际上是JS的一部分,是的,它被浏览器识别,即使它存在,它也找不到标签('form')。所以我不得不用另一种方式找到表格。 好吧,是的,把博客代码当作一个起点,显然需要更多的错误检查。至少它是草根的并且很容易调试(记录响应等)。

以上是关于有没有办法使用 cypress/JS 以编程方式通过 Keycloak 登录应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法以编程方式列出所有 gradle 依赖项?

有没有办法以编程方式启用 POP

有没有办法以编程方式配置 MDB?

有没有办法以编程方式(使用宏)在 calc open office 中附加文件(.txt)?

有没有办法以编程方式访问 iOS 图像描述器?

有没有办法以编程方式在 TextView 中选择文本?