如何在nestjs graphql中实现用户保护
how to implement user guards in nestjs graphql
我正在尝试获取当前用户,但在解析器中我未定义,在 jwt 策略中我使用 tokne 获取用户 ibject 但在解析器中用户未定义
auth guard
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';
import { AuthenticationError } from 'apollo-server-core';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
const { req } = ctx.getContext();
return super.canActivate(
new ExecutionContextHost([req]),
);
}
handleRequest(err: any, user: any) {
if (err || !user) {
throw err || new AuthenticationError('GqlAuthGuard');
}
return user;
}
}
用户装饰器
import {createParamDecorator} from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data, req) => req.user )
;
应用模块
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
signOptions: {
expiresIn: 3600,
},
}),
SharedModule,
AuthModule,
GraphQLModule.forRoot({
autoSchemaFile: 'schema.gql',
context: ({ req }) => ({ req })
}),
MongooseModule.forRoot(process.env.MONGO_URI,
{
useNewUrlParser: true ,
useUnifiedTopology: true
}),
// RewardsModule,
OrdersModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
解析器
import {User} from "src/types/user";
import {GqlAuthGuard} from "../guards/graphql.auth.guard";
@Resolver()
export class OrdersResolver {
constructor(
private orderService: OrdersService
) {
}
@Query(returns => [Order])
@UseGuards(GqlAuthGuard)
listOrders(@CurrentUser() user: User): Promise<Order> {
console.log(user)
return this.orderService.listOrdersByUser(user.id);
}
}
我也尝试实施此处解释的解决方案,但我仍然遇到同样的错误
在 Nest v7 中,createParamDecorator
函数得到了更新。现在,而不是使用
export const CurrentUser = createParamDecorator(
(data, req) => req.user )
;
你应该改用这样的东西:
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const gqlCtx = GqlExecutionContext.create(ctx);
const request = gqlCtx.getContext().req;
return request.user;
},
);
为此,您还需要
context: ({req}) => ({req})
在您的 GraphqlModule
配置中。
这是完整的代码:
@Injectable()
export class RolesGuard_ implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const ctx = GqlExecutionContext.create(context);
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = ctx.getContext().req;
return requiredRoles.some((role) => user.role?.includes(role));
}
}
这是我根据文档GraphqlJwtAuthGuard
使用的内容:
@Injectable()
export class GqlJwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super();
}
canActivate(ctx: ExecutionContext) {
const context = GqlExecutionContext.create(ctx);
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
const { req } = context.getContext();
return super.canActivate(new ExecutionContextHost([req])); // NOTE
}
}
我正在尝试获取当前用户,但在解析器中我未定义,在 jwt 策略中我使用 tokne 获取用户 ibject 但在解析器中用户未定义
auth guard
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';
import { AuthenticationError } from 'apollo-server-core';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
const { req } = ctx.getContext();
return super.canActivate(
new ExecutionContextHost([req]),
);
}
handleRequest(err: any, user: any) {
if (err || !user) {
throw err || new AuthenticationError('GqlAuthGuard');
}
return user;
}
}
用户装饰器
import {createParamDecorator} from '@nestjs/common';
export const CurrentUser = createParamDecorator(
(data, req) => req.user )
;
应用模块
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
signOptions: {
expiresIn: 3600,
},
}),
SharedModule,
AuthModule,
GraphQLModule.forRoot({
autoSchemaFile: 'schema.gql',
context: ({ req }) => ({ req })
}),
MongooseModule.forRoot(process.env.MONGO_URI,
{
useNewUrlParser: true ,
useUnifiedTopology: true
}),
// RewardsModule,
OrdersModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
解析器
import {User} from "src/types/user";
import {GqlAuthGuard} from "../guards/graphql.auth.guard";
@Resolver()
export class OrdersResolver {
constructor(
private orderService: OrdersService
) {
}
@Query(returns => [Order])
@UseGuards(GqlAuthGuard)
listOrders(@CurrentUser() user: User): Promise<Order> {
console.log(user)
return this.orderService.listOrdersByUser(user.id);
}
}
我也尝试实施此处解释的解决方案
在 Nest v7 中,createParamDecorator
函数得到了更新。现在,而不是使用
export const CurrentUser = createParamDecorator(
(data, req) => req.user )
;
你应该改用这样的东西:
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const gqlCtx = GqlExecutionContext.create(ctx);
const request = gqlCtx.getContext().req;
return request.user;
},
);
为此,您还需要
context: ({req}) => ({req})
在您的 GraphqlModule
配置中。
这是完整的代码:
@Injectable()
export class RolesGuard_ implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const ctx = GqlExecutionContext.create(context);
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = ctx.getContext().req;
return requiredRoles.some((role) => user.role?.includes(role));
}
}
这是我根据文档GraphqlJwtAuthGuard
使用的内容:
@Injectable()
export class GqlJwtAuthGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super();
}
canActivate(ctx: ExecutionContext) {
const context = GqlExecutionContext.create(ctx);
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
context.getHandler(),
context.getClass(),
]);
if (isPublic) {
return true;
}
const { req } = context.getContext();
return super.canActivate(new ExecutionContextHost([req])); // NOTE
}
}