Azure Active Directory 认证
你将学到
- 如何配置 Cypress 来测试 Azure Active Directory 网页应用
- 如何使用
cy.origin()
进行 Azure Active Directory 认证
本指南适用于测试使用 Azure Active Directory (AAD) 进行用户认证的单页应用 (SPA)。在本指南中,网页应用使用 Microsoft 认证库 @azure/msal-browser
包来代理此认证。
本指南也可作为使用 Cypress 测试其他使用 Azure Active Directory 服务的网页应用的基础,例如使用 React、Angular 或 Vue 框架的应用。
Microsoft AAD 应用设置
在本指南中,我们主要关注如何配置 Cypress 来测试 Azure Active Directory 网页应用。请克隆 Microsoft Identity JavaScript Tutorial 并按照步骤设置你的应用。
设置完成后,你需要在 App/index.html
文件中进行一些修改:
- 移除
<script>
标签中的所有integrity
属性。这是为了防止任何 SRI 属性不匹配,因为 Cypress 必须重写任何 框架破坏代码。这仅在测试应用时推荐。 - 取消注释
authRedirect.js
的<script>
标签并注释掉authPopup.js
的<script>
标签。认证 弹窗 在 Cypress 中无法工作。
在 server.js
中,你会看到对 express-rate-limit
的引用,它限制每个窗口在 15 分钟内最多 100 个请求。在测试中,你的应用可能会超过这个限制,因为你将重新加载应用并向代理/验证认证发起请求。对于本演示,你可以:
- 移除速率限制代码(仅推荐用于演示目的)。
- 实施一个策略来增加测试时的速率限制。
完成后,你的 SPA 应该运行在 http://localhost:3000
上,并正确配置为与 Azure Active Directory 和 Cypress 一起运行。
配置 Cypress 使用 Microsoft AAD
为了在测试中访问测试用户凭据,我们需要配置 Cypress 使用 Azure Active Directory 用户凭据,这些凭据应设置在项目根目录的 cypress.env.json
文件中。
{
"aad_username": "AAD_USERNAME",
"aad_password": "AAD_PASSWORD",
"aad_name": "AAD_NAME"
}
此外,为了与 Azure Active Directory 进行认证,你需要在 e2e 配置中启用 experimentalModifyObstructiveThirdPartyCode
配置选项。如果不启用,你的认证流程将进入无限 重定向循环。
- cypress.config.js 文件
- cypress.config.ts 文件
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
experimentalModifyObstructiveThirdPartyCode: true,
},
})
import { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
experimentalModifyObstructiveThirdPartyCode: true,
},
})
使用 cy.origin()
登录
接下来,我们将编写一个名为 loginToAAD
的自定义命令来执行 Azure Active Directory 登录。此命令将使用 cy.origin()
来:
- 导航到
login.microsoftonline.com
上的 Azure Active Directory 登录页面 - 输入用户凭据
- 登录并重定向回演示应用
- 使用
cy.session()
缓存结果
function loginViaAAD(username: string, password: string) {
cy.visit('http://localhost:3000/')
cy.get('button#signIn').click()
// 登录到你的 AAD 租户。
cy.origin(
'login.microsoftonline.com',
{
args: {
username,
},
},
({ username }) => {
cy.get('input[type="email"]').type(username, {
log: false,
})
cy.get('input[type="submit"]').click()
}
)
// 根据用户及其在 Microsoft 的注册方式,来源可能会转到 live.com
cy.origin(
'login.live.com',
{
args: {
password,
},
},
({ password }) => {
cy.get('input[type="password"]').type(password, {
log: false,
})
cy.get('input[type="submit"]').click()
cy.get('#idBtn_Back').click()
}
)
// 确保 Microsoft 已将我们重定向回示例应用,并已登录用户。
cy.url().should('equal', 'http://localhost:3000/')
cy.get('#welcome-div').should(
'contain',
`Welcome ${Cypress.env('aad_username')}!`
)
}
Cypress.Commands.add('loginToAAD', (username: string, password: string) => {
const log = Cypress.log({
displayName: 'Azure Active Directory Login',
message: [`🔐 Authenticating | ${username}`],
autoEnd: false,
})
log.snapshot('before')
loginViaAAD(username, password)
log.snapshot('after')
log.end()
})
现在,我们可以在测试中使用 loginToAAD
命令。以下是我们通过 Azure Active Directory 登录用户并运行基本健全性检查的测试。
describe('Azure Active Directory Authentication', () => {
beforeEach(() => {
// 使用我们的自定义命令通过示例 SPA 登录到 Azure Active Directory
cy.loginToAAD(Cypress.env('aad_username'), Cypress.env('aad_password'))
cy.visit('http://localhost:3000')
})
it('verifies the user logged in has the correct name', () => {
cy.get('#table-body-div td:contains("name") + td').should(
'contain',
`${Cypress.env('aad_name')}`
)
})
it('verifies the user logged in has the correct preferred name', () => {
cy.get('#table-body-div td:contains("preferred_username") + td').should(
'contain',
`${Cypress.env('aad_username')}`
)
})
})
我们现在有了可用的认证和测试!但我们在每个测试前都进行登录,这不仅耗时,还可能导致由于请求数量过多而触发 API 速率限制。
为此,我们可以重构我们的登录命令,利用 cy.session()
来存储我们登录用户的令牌和/或 cookie,这样我们就不必在每个测试前重新认证。
Cypress.Commands.add('loginToAAD', (username: string, password: string) => {
cy.session(
`aad-${username}`,
() => {
const log = Cypress.log({
displayName: 'Azure Active Directory Login',
message: [`🔐 Authenticating | ${username}`],
// @ts-ignore
autoEnd: false,
})
log.snapshot('before')
loginViaAAD(username, password)
log.snapshot('after')
log.end()
},
{
validate: () => {
// 这是本演示中非常基本的会话验证形式。
// 根据你的需求,可能需要更详细的验证
cy.visit('http://localhost:3000')
cy.get('#welcome-div').should(
'contain',
`Welcome ${Cypress.env('aad_username')}!`
)
},
}
)
})
通过使用 cy.session()
,我们的测试现在应该运行得更快!
我们希望本指南能帮助你开始使用 cy.origin()
和 cy.session()
。如果你在遵循本指南时遇到任何问题,或有任何反馈,请告诉我们并提交 Github issue。祝你测试愉快!