/** * GraphQL Context - Apollo Router 下传的请求上下文 * * Apollo Router 通过 headers 传递以下信息到子图: * - authorization: JWT token(透传) * - x-user-id: 已认证用户 ID * - x-user-role: 用户角色 * - x-dataScope: 数据范围(ALL / SCHOOL / GRADE / CLASS / STUDENT) * - x-request-id: 请求追踪 ID * * 子图从 HTTP headers 提取后构造 GraphqlContext,注入 Resolver。 */ export type DataScope = "ALL" | "SCHOOL" | "GRADE" | "CLASS" | "STUDENT"; export interface GraphqlContextInput { userId?: string; userRole?: string; dataScope?: DataScope; requestId?: string; jwt?: string; } export class GraphqlContext { readonly userId?: string; readonly userRole?: string; readonly dataScope: DataScope; readonly requestId: string; readonly jwt?: string; constructor(input: GraphqlContextInput) { this.userId = input.userId; this.userRole = input.userRole; this.dataScope = input.dataScope ?? "ALL"; this.requestId = input.requestId ?? "unknown"; this.jwt = input.jwt; } /** 是否管理员(全量可见) */ get isAdmin(): boolean { return this.dataScope === "ALL" || this.userRole === "admin"; } /** 是否已认证 */ get isAuthenticated(): boolean { return !!this.userId; } /** 从 HTTP headers 构造(NestJS @Context 提取) */ static fromHeaders( headers: Record, ): GraphqlContext { return new GraphqlContext({ userId: headers["x-user-id"], userRole: headers["x-user-role"], dataScope: headers["x-datapscope"] as DataScope | undefined, requestId: headers["x-request-id"], jwt: headers["authorization"]?.replace(/^Bearer\s+/i, ""), }); } }