NestJS:如何从从 JWT AuthGuard 扩展的 GraphQL 自定义 Guard 中的请求中获取用户

ghi*_*ing 4 typescript graphql nestjs

我使用 Passport 和 GraphQL,如果我使用自己的自定义防护来获取用户的角色,那么它就不起作用。我无权通过 Guard 中的请求访问用户,这是故意的吗?我认为它应该是请求的一部分(我对 NestJS 完全陌生),那么为什么我不能得到它呢?我想直接从用户对象获取用户的角色,并且只允许具有管理员权限的用户执行特定的路由,例如完整的用户列表。

这是我的 GraphQL 守卫,控制台日志总是返回未定义

@Injectable()
export class GraphqlPassportAuthGuard extends AuthGuard('jwt') {
  roles: string[];

  constructor(roles?: string | string[]) {
    super();
    this.roles = Array.isArray(roles) ? roles : [roles];
  }

  canActivate(context: ExecutionContext): boolean {
    const ctx = GqlExecutionContext.create(context);
    const req = ctx.getContext().req;
    console.log('graphql guard user', req && req.user)
    return true;
  }

  getRequest(context: ExecutionContext) {
    const ctx = GqlExecutionContext.create(context);
    const req = ctx.getContext().req;
    console.log('graphql guard user', req && req.user)
    return req;
  }
}
Run Code Online (Sandbox Code Playgroud)

我尝试通过以下代码使用它

export const CurrentUser = createParamDecorator(
  (data, [root, args, ctx, info]) => {
    return ctx.req.user;
  },
);

@Resolver()
export class UsersResolver {
  constructor() { } 

  @Query(() => UserDto)
  @UseGuards(GraphqlPassportAuthGuard)
  whoAmI(@CurrentUser() user: User) {
    return user;
  }
}
Run Code Online (Sandbox Code Playgroud)

app.module.ts

@Module({
  imports: [
    GraphQLModule.forRoot({
      autoSchemaFile: 'schema.gql',
      context: ({ req }) => ({ req }),
    }),
    // ...
});
Run Code Online (Sandbox Code Playgroud)

我可以使用自定义装饰器获取用户@CurrentUser(),但无法获取防护内的用户对象。我正在尝试从请求中获取用户,但这在 Guard 中是否可能?我尝试了很多事情,我不知道该怎么办了。

我还尝试使用不同的代码执行另一个角色防护,并且我再次尝试从请求中获取用户,但无法从请求中获取用户。

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) { }

  canActivate(context: ExecutionContext): boolean {
    const handler = context.getHandler();
    const http = context.switchToHttp();
    const request = context.switchToHttp().getRequest();
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    console.log('rolesGuard', roles, request && request.user)
    if (!roles || !request || !request.user) {
      return true;
    }
    const user = request && request.user;
    const hasRole = () =>
      user.roles.some(role => !!roles.find(item => item === role));

    return user && user.roles && hasRole();
  }
}
Run Code Online (Sandbox Code Playgroud)

小智 5

GraphqlPassportAuthGuard.canActivate()应该调用await super.canActivate(context),并更改 的返回值类型Promise<boolean>,这是 @nestjs/passportAuthGuard将用户放入 Request 对象的位置。

如果由于某种原因,您不希望在用户未经身份验证时抛出守卫,则还必须覆盖AuthGuard.handleRequest(err, user, info, context)