You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure AD Cypress认证报错AADSTS9002327,求助解决方法

解决Cypress测试Azure AD SPA应用时的AADSTS9002327错误

错误原因

AADSTS9002327错误的核心是:Azure AD为**单页应用(SPA)颁发的令牌,仅允许通过跨域请求(XHR/fetch)**进行兑换,而直接通过cy.origin模拟登录后,Cypress的环境无法正确触发SPA所需的跨域令牌交换流程,导致认证失败。

解决方案:模拟SPA的OAuth2授权码流+PKCE

SPA类型的Azure AD应用必须使用授权码流+PKCE进行认证,我们需要在Cypress中手动模拟这一流程,确保令牌交换符合Azure AD的要求。

步骤1:编写Cypress登录命令

在cypress/support/auth.js中添加以下命令:

// 生成PKCE所需的code_verifier
function generateCodeVerifier() {
  const array = new Uint32Array(56 / 2);
  window.crypto.getRandomValues(array);
  return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join('');
}

// 基于code_verifier生成code_challenge
function generateCodeChallenge(codeVerifier) {
  return crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier))
    .then(buffer => btoa(String.fromCharCode(...new Uint8Array(buffer))))
    .then(base64 => base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''));
}

// 封装Azure AD登录命令
Cypress.Commands.add('loginToAzureAD', async () => {
  const tenantId = Cypress.env('azureTenantId');
  const clientId = Cypress.env('azureClientId');
  const redirectUri = Cypress.env('azureRedirectUri');
  const scope = 'openid profile email';
  const username = Cypress.env('azureUsername');
  const password = Cypress.env('azurePassword');

  // 生成PKCE参数
  const codeVerifier = generateCodeVerifier();
  const codeChallenge = await generateCodeChallenge(codeVerifier);

  // 访问Azure AD授权端点
  cy.visit(`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize?` +
    `client_id=${clientId}&` +
    `response_type=code&` +
    `redirect_uri=${encodeURIComponent(redirectUri)}&` +
    `scope=${encodeURIComponent(scope)}&` +
    `code_challenge_method=S256&` +
    `code_challenge=${codeChallenge}`);

  // 在Azure AD域名下处理登录交互
  cy.origin('login.microsoftonline.com', { args: { username, password } }, ({ username, password }) => {
    // 输入邮箱
    cy.get('input[type="email"]').should('be.visible').type(username);
    cy.get('input[type="submit"]').should('be.visible').click();

    // 输入密码
    cy.get('input[type="password"]').should('be.visible').type(password);
    cy.get('input[type="submit"]').should('be.visible').click();

    // 跳过"保持登录"提示
    cy.get('#idBtn_Back').should('be.visible').click();
  });

  // 从重定向URL中提取授权码
  cy.url().then(url => {
    const code = new URL(url).searchParams.get('code');
    expect(code).to.not.be.null;

    // 通过跨域请求兑换令牌
    cy.request({
      method: 'POST',
      url: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
      form: true,
      body: {
        client_id: clientId,
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: redirectUri,
        code_verifier: codeVerifier,
        scope: scope
      }
    }).then(response => {
      // 将令牌存入localStorage,模拟SPA的存储逻辑
      cy.window().then(window => {
        window.localStorage.setItem('access_token', response.body.access_token);
        window.localStorage.setItem('id_token', response.body.id_token);
      });
    });
  });
});

步骤2:配置Cypress环境变量

在cypress.config.js或cypress.env.json中添加敏感配置:

{
  "azureTenantId": "你的租户ID",
  "azureClientId": "SPA应用的客户端ID",
  "azureRedirectUri": "应用注册中设置的重定向URI",
  "azureUsername": "测试账号邮箱",
  "azurePassword": "测试账号密码"
}

步骤3:在测试用例中使用登录命令

describe('Azure AD 保护的SPA应用测试', () => {
  beforeEach(() => {
    // 使用session持久化登录状态,避免重复登录
    cy.session('azure-ad-session', () => {
      cy.loginToAzureAD();
    }, {
      validate() {
        cy.visit('/');
        cy.contains('欢迎页内容').should('be.visible');
      }
    });
    cy.visit('/');
  });

  it('应该成功加载受保护页面', () => {
    cy.get('.protected-content').should('be.visible');
  });
});

关键注意事项

  • 确保Azure AD应用注册类型为单页应用(SPA),且重定向URI与配置中的azureRedirectUri完全一致
  • 开启Cypress的跨域支持:在cypress.config.js中设置chromeWebSecurity: false(仅测试环境使用)
  • 不要硬编码敏感信息,始终使用Cypress环境变量存储
  • 如果应用有自定义的令牌存储键名,需要对应修改localStorage.setItem的键

内容的提问来源于stack exchange,提问作者teddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 23:34:53