feat(shared-ts): federation shared utilities for apollo subgraphs
- 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
This commit is contained in:
60
packages/shared-ts/src/federation/context.ts
Normal file
60
packages/shared-ts/src/federation/context.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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, ""),
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user