NestJS Получить текущего пользователя в распознавателе GraphQL, прошедшего аутентификацию с помощью JWT - PullRequest
3 голосов
/ 20 марта 2019

В настоящее время я внедряю аутентификацию JWT с помощью Passport.js в приложение NestJS.

В некоторых из моих распознавателей GraphQL мне нужен доступ к аутентифицированному пользователю.Я знаю, что аттестат присоединит аутентифицированного пользователя к объекту запроса (по крайней мере, я надеюсь, что это правильно), но я не знаю, как получить доступ к объекту запроса внутри распознавателя.

Я следовал за проблемой https://github.com/nestjs/nest/issues/1326 и упомянутой ссылкой https://github.com/ForetagInc/fullstack-boilerplate/tree/master/apps/api/src/app/auth внутри номера.Я видел некоторый код, который использует @Res() res: Request в качестве параметра метода в методах распознавания GraphQL, но я всегда получаю undefined для res.

Это текущие реализации, которые у меня есть:

GQLAuth

import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
import { AuthenticationError } from 'apollo-server-core';

@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
  canActivate(context: ExecutionContext) {
    const ctx = GqlExecutionContext.create(context);
    const { req } = ctx.getContext();
    console.log(req);

    return super.canActivate(new ExecutionContextHost([req]));
  }

  handleRequest(err: any, user: any) {
    if (err || !user) {
      throw err || new AuthenticationError('GqlAuthGuard');
    }
    return user;
  }
}

Resolver, которому требуется доступ к текущему пользователю

import { UseGuards, Req } from '@nestjs/common';
import { Resolver, Query, Args, Mutation, Context } from '@nestjs/graphql';
import { Request } from 'express';

import { UserService } from './user.service';
import { User } from './models/user.entity';
import { GqlAuthGuard } from '../auth/guards/gql-auth.guard';

@Resolver(of => User)
export class UserResolver {
  constructor(private userService: UserService) {}

  @Query(returns => User)
  @UseGuards(GqlAuthGuard)
  whoami(@Req() req: Request) {
    console.log(req);
    return this.userService.findByUsername('aw');
  }
}

Стратегия JWT

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';
import { JwtPayload } from './interfaces/jwt-payload.interface';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: process.env.SECRET,
    });
  }

  async validate(payload: JwtPayload) {
    const user = await this.authService.validateUser(payload);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

Авторизация и создание токенов JWT работает отлично.GraphQL guard также отлично работает для методов, которым не требуется доступ к пользователю.Но для методов, которым нужен доступ к аутентифицированному пользователю, я не вижу способа его получить.

Есть ли способ сделать что-то подобное?

1 Ответ

10 голосов
/ 21 марта 2019

Как всегда, после того, как вы провели поиск часов / дней, не найдя решения, и, наконец, отправив вопрос в StackOverflow, вы найдете ответ в течение нескольких минут ...

https://github.com/nestjs/graphql/issues/48#issuecomment-420693225 указал мне правильное направление создания пользовательского декоратора

// user.decorator.ts
import { createParamDecorator } from '@nestjs/common';

export const User = createParamDecorator(
  (data, [root, args, ctx, info]) => ctx.req.user,
);

И затем используйте это в моем методе распознавателя:

 import { User as CurrentUser } from './user.decorator';

 @Query(returns => User)
  @UseGuards(GqlAuthGuard)
  whoami(@CurrentUser() user: User) {
    console.log(user);
    return this.userService.findByUsername(user.username);
  }

Теперь все работает как положено,Таким образом, все кредиты этого ответа идет к https://github.com/cschroeter

...