freeCodeCamp E2E 测试中 API 请求如何携带 CSRF token?

📅 发布时间:2026/9/10 5:08:54
freeCodeCamp E2E 测试中 API 请求如何携带 CSRF token?
freeCodeCamp E2E 测试中 API 请求如何携带 CSRF token【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp在 freeCodeCamp 仓库的e2e/目录下新增或修改 Playwright 测试时只要测试需要向 API 发送POST/PUT请求例如保存进度、更新设置、删除账户请求就必须携带 CSRF token否则会被 API 的 CSRF 保护拦截。本文说明该仓库 e2e 套件中 token 的来源、携带方式和验证方式让你在新写的测试用例中直接沿用同一套模式。API 侧的 CSRF 机制token 从哪来、校验什么先看服务端约定理解 e2e 代码里为什么这样取值。在 csrf 插件 中定义了两个常量CSRF_COOKIE csrf_tokencookie 名CSRF_HEADER csrf-token请求头名。插件注册了fastify/csrf-protection并通过getToken: req req.headers[CSRF_HEADER]声明token 只从csrf-token请求头读取。同时除/signout外的所有请求都会触发onRequest钩子把新生成的 token 写入csrf_tokencookie属性为sameSite: strict、signed: false、httpOnly: false。源码注释解释了最后一点cookie 必须可被客户端读取才能在下一个请求中放进请求头发回。校验钩子在 api/src/app.ts 中启用需要认证的路由组在onRequest阶段挂上了fastify.csrfProtection。插件配套测试 api/src/plugins/csrf.test.ts 记录了三种结果缺少_csrfsecret cookie返回 403csrf_token与 secret 不匹配无效 token返回 403携带有效csrf_tokencookie 和csrf-token头请求正常处理返回 200。_csrfcookie 是fastify/csrf-protection下发的 secret与csrf_token一起随会话存在e2e 侧只需要拿到csrf_token并放进头里。e2e 侧token 随登录后的 storageState 一起保存e2e 测试不单独请求 token 端点而是复用登录会话里的 cookie。链路如下。e2e/playwright.config.ts 启动时先用 dotenv 加载仓库根目录的.envbaseURL取process.env.HOME_LOCATION默认http://127.0.0.1:8000并全局设置storageState: playwright/.auth/certified-user.json。API_LOCATION在 sample.env 中给出的本地值是http://localhost:3000。e2e/global-setup.ts 定义了setup项目beforeAll中先执行node ../tools/scripts/seed/seed-demo-user播种演示用户会向数据库写入种子数据是本地开发环境操作然后request.get(process.env.API_LOCATION /signin)完成登录最后request.storageState({ path: playwright/.auth/certified-user.json })把整个会话的 cookie——包括csrf_token——落盘。所有依赖setup的浏览器项目加载这份 storage state 后请求上下文里就同时具备了登录凭证和 CSRF cookie。也就是说只要走global-setup.ts的 setup 流程登录过request.storageState()里就能找到csrf_tokencookie。测试代码中的两种携带方式方式一authedRequest辅助函数对大多数已登录用户调受保护接口的用例直接复用 e2e/utils/request.ts 中的authedRequestconst csrfToken (await request.storageState()).cookies.find( c c.name csrf_token )?.value; expect(csrfToken).toBeTruthy(); const res await requestmethod, { data, headers: { csrf-token: csrfToken! } } ); expect(res.status()).toBe(200);它的约束是明确的只接受method: post | put和data: Recordstring, unknown参数endpoint没有前导/时会自动补上从当前请求上下文的 storage state 里找csrf_tokencookie找不到时expect(csrfToken).toBeTruthy()直接让测试失败请求发出后断言状态码为 200。仓库中多个用例已经这样调用例如 e2e/editor.spec.ts 顶部就是import { authedRequest } from ./utils/request;其他调用方还有 e2e/projects.spec.ts、e2e/hotkeys.spec.ts、e2e/completion-modal.spec.ts 等可以打开参考具体传参。方式二isolatedUserfixture测试用独立新账号当用例需要一个全新的、与其他测试互不影响的账号时使用 e2e/fixtures/isolated-user.ts 导出的 fixture。它内部自己完成了同样的登录拿 cookie、调接口带头流程用randomUUID()生成一次性邮箱创建空 cookie 上下文GET /signin?email...maxRedirects: 0要求返回 302 且 cookie 中出现jwt_access_token否则抛错说明登录失败测试 teardown 时调用/account/delete清理账号请求体为空、头里带csrf-token: csrfToken。这里有两处针对 token 的失败处理token 缺失时抛出Could not clean up the isolated user: CSRF token missing.删除响应不是 200 时抛出包含状态码和响应体的错误。该文件里的getCsrfToken就是取值逻辑的最小实现const getCsrfToken async (request: APIRequestContext) (await request.storageState()).cookies.find( cookie cookie.name csrf_token )?.value;新写一个独立用户用例时导入这里的test即可使用isolatedUser含email和storageState两个字段。如何验证携带是否正确测试通过即验证authedRequest已断言 200API 侧插件测试 api/src/plugins/csrf.test.ts 表明 200 与 403 的分界就是 token 是否有效。token 缺失的失败信号expect(csrfToken).toBeTruthy()或 fixture 的CSRF token missing.异常说明当前请求上下文里没有登录会话storage state 未加载、或上下文是空的且未先登录而不是网络问题。响应 403对应 API 侧_csrfsecret 缺失或 token 无效的情况e2e 里通常表现为 storage state 过期或会话不完整重新跑 setup 项目重新登录可刷新csrf_token。运行与限制在e2e/目录下e2e/package.json 提供的入口是pnpm playwright:run该脚本实际执行turbo setup playwright test先运行global-setup.ts播种并登录再跑各浏览器项目。配置中的webServer还会用 Docker 拉起 mailpitdocker run --rm -p 1025:1025 -p 8025:8025 axllent/mailpit供发邮件类测试接收邮件因此运行环境需要可用的 Docker 和已按 sample.env 配置好.env的本地 API 服务。两点边界需要留意isolatedUserfixture 的 teardown 会真实调用/account/delete删除刚创建的账号这是预期的清理行为不是额外破坏csrf_tokencookie 的sameSite: strict属性意味着该 cookie 只随同源请求回传e2e 中始终通过request.storageState()读取 cookie 值再显式放入csrf-token头而不是依赖浏览器自动回传。如果你只是要在浏览器 UI 层调试同样的机制api/src/app.ts 中 Swagger UI 的requestInterceptor展示的是同一模式从document.cookie里找出csrf_token写入req.headers[csrf-token]后再发请求。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考