我希望
@Context
托管一些身份验证信息,例如令牌、用户、..
我创建了一个 TGqlContext
类型,它在初始化 graphql 时被传递
export type TGqlContext = {
req: Request;
res: Response;
accessToken: string;
refreshToken: string;
user?: UserDTO | undefined;
};
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
include: [ProductsModule, AuthModule, TransactionsModule],
buildSchemaOptions: {
dateScalarMode: "timestamp",
},
autoSchemaFile: true,
context: (ctx: TGqlContext) => ctx,
}),
成功登录后,我想使用身份验证数据设置上下文。我正在尝试使用拦截器,因为它可以访问解析器响应。
虽然登录解析器的结果被很好地拦截,并且没有未定义,但在某些查询中使用@Context时,上下文数据仍然是未定义的。
我如何在登录后设置这些上下文值?
登录突变,带有拦截器
@UseInterceptors(LoggingInterceptor)
@Mutation(() => AuthDTO)
async login(@Args("credentials") credentials: AuthLoginInputType): Promise<AuthDTO> {
const log = await this.authService.login(credentials);
if (log.isValid) {
this.authService.accessToken = log.accessToken;
this.authService.refreshToken = log.refreshToken;
this.authService.user = log.user;
return {
accessToken: log.accessToken,
refreshToken: log.refreshToken,
user: log.user,
};
} else {
this.authService.accessToken = "";
this.authService.refreshToken = "";
this.authService.user = undefined;
throw new HttpException(`${log.error} - ${log.message}`, log.httpStatus);
}
}
拦截器
export class LoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger(LoggingInterceptor.name);
constructor() {
this.logger.log("inter");
}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> | Promise<Observable<any>> {
const ctx = GqlExecutionContext.create(context).getContext<TGqlContext>();
const resu = next.handle().pipe(
map((res: TGqlContext) => {
this.logger.log(res.accessToken); //<--- here the data are NOT undefined
ctx.accessToken = res.accessToken;
ctx.refreshToken = res.accessToken;
ctx.user = res.user;
return res;
}),
catchError((err: any) => {
throw new HttpException(err.message, HttpStatus.BAD_REQUEST);
})
);
return resu;
}
}
尝试获取这些上下文数据的查询示例
@Query(() => AuthDTO)
async me(@Context() ctx: TGqlContext): Promise<AuthDTO> {
this.logger.log(ctx.accessToken); // <--- here data is undefined...
const mee: AuthDTO = {
accessToken: this.authService.accessToken,
refreshToken: this.authService.refreshToken,
user: this.authService.user,
};
return mee;
}
我通过在请求的会话中添加 auth 数据找到了解决方案,而不是在 graphql 上下文的根目录中添加这些数据。在我看来这不是最有价值的解决方案
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
include: [ProductsModule, AuthModule, TransactionsModule],
buildSchemaOptions: {
dateScalarMode: "timestamp",
},
autoSchemaFile: true,
context: ({ req }: { req: Request }) => ({ req }),
}),
在登录解析器中
@Mutation(() => AuthDTO)
async login(@Context() ctx: TGqlContext, @Args("credentials") credentials: AuthLoginInputType): Promise<AuthDTO> {
const log = await this.authService.login(credentials);
if (log.isValid) {
this.authService.accessToken = log.accessToken;
this.authService.refreshToken = log.refreshToken;
this.authService.user = log.user;
ctx.req.session.accessToken = log.accessToken;
ctx.req.session.refreshToken = log.refreshToken;
ctx.req.session.user = log.user;
return {
accessToken: log.accessToken,
refreshToken: log.refreshToken,
user: log.user,
};
} else {
throw new HttpException(`${log.error} - ${log.message}`, log.httpStatus);
}
}