- RouterAuthGuard: validate Router-Authorization header (ADR-036) - DataLoader factory: request-scoped batching (ADR-035) - ScopeTokenService: Redis-backed scope token (ADR-041) - GraphqlContext: build context from HTTP headers - FederationExceptionFilter: HTTP-to-GraphQL error mapping
61 lines
1.7 KiB
TypeScript
61 lines
1.7 KiB
TypeScript
/**
|
||
* 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<string, string | undefined>,
|
||
): 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, ""),
|
||
});
|
||
}
|
||
}
|