Files
Edu/apps/portal-shell/src/instrumentation.ts
SpecialX cfb7b005fd feat(portal-shell): v2.1 P0 auth + middleware + login + graphql proxy
- 新增 ARCHITECTURE.md v3.0:portal-shell 架构权威文档
  涵盖 §3.4 V3-A2/A3 认证链、§4 GraphQL 联邦、§5 安全、
  §6 部署、§10 P0-P3 验收清单
- 新增 middleware.ts:认证 + 路由门禁
  httpOnly cookie edu_session(JWT)读取
  DEV_MODE 合成 dev-user/teacher 身份(NODE_ENV!=production &&
  NEXT_PUBLIC_DEV_MODE=true)
  生产模式 jose JWKS RS256 验签(iss/aud 校验)
  路由权限位图注入 x-user-id/x-user-role/x-user-permissions 头
  /shell/** 强制 checkRoutePermission,拒绝跳 /shell/forbidden
- 新增 instrumentation.ts:生产环境 DEV_MODE 强制 false
  防止生产环境误开 DEV_MODE 合成身份
- 新增 app/api/auth/login/route.ts + logout/route.ts
  登录走 api-gateway /v1/iam/login
  设置 httpOnly + Secure + SameSite=Strict cookie
- 新增 app/api/graphql/route.ts:同域 GraphQL 代理
  转发到 apollo-router,注入 router-authorization 头
- 新增 app/login/page.tsx + login-form.tsx
  zod 表单校验,next 参数支持
- 新增 app/shell/forbidden/page.tsx:403 页面
- 更新 route-permissions.ts:补全 P0 路由权限映射
- 更新 permission-bitmap.ts(shared-ts):位图编码/解码
- 更新 apollo-client.ts:DEV_MODE APQ 关闭,错误处理
- 更新 config-fetcher.ts:config-service 直连降级
- 更新 ApolloProvider.tsx:SSR/RSC 兼容
- 更新 eslint.config.js:design-tokens/no-hardcoded-fonts
  白名单调整
2026-07-22 11:35:36 +08:00

39 lines
1.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Next.js Instrumentation Hook启动期守卫
*
* 关联ARCHITECTURE.md §3.4 V3-A2 / §6.1 / §10 P0-5
*
* 在生产环境NODE_ENV=productionDEV_MODE 必须为 false
* 若 NEXT_PUBLIC_DEV_MODE=true或非 "false")则启动即抛错退出,
* 防止"生产永久绕过认证"(见 §1.3-F4 / §6.1)。
*
* 验收命令:
* NODE_ENV=production NEXT_PUBLIC_DEV_MODE=true pnpm start
* → 进程退出stderr 输出包含 "NEXT_PUBLIC_DEV_MODE must be false in production"
*
* 开发态NODE_ENV !== "production")放行,由 middleware 提供 dev-token 合成身份。
*/
export async function register(): Promise<void> {
const nodeEnv = process.env.NODE_ENV ?? "";
const devModeRaw = process.env.NEXT_PUBLIC_DEV_MODE ?? "";
if (nodeEnv !== "production") {
return;
}
// 仅生产环境校验DEV_MODE 必须显式为 "false"(或等价 falsy
const devModeEnabled =
devModeRaw !== "false" && devModeRaw !== "0" && devModeRaw !== "";
if (devModeEnabled) {
const msg =
"[portal-shell] FATAL: NEXT_PUBLIC_DEV_MODE must be false in production " +
`(got NEXT_PUBLIC_DEV_MODE=${JSON.stringify(devModeRaw)}). ` +
"Aborting startup to prevent authentication bypass " +
"(ARCHITECTURE.md §10 P0-5).";
console.error(msg);
// 非零退出码,触发进程管理器/容器重启策略
process.exit(1);
}
}