Получение данных пользователя с помощью Guards (Roles, JWT) - PullRequest
0 голосов
/ 22 ноября 2018

Документация здесь довольно тонкая, поэтому я столкнулся с проблемой.Я пытаюсь использовать Guards для защиты контроллера или его действий, поэтому я буду просить о роли аутентифицированных запросов (от JWT).В моем auth.guard.ts я спрашиваю "request.user", но он пуст, поэтому я не могу проверить роль пользователей.Я не знаю, как определить "request.user".Вот мой модуль авторизации и его импорт.

auth.controller.ts

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { RolesGuard } from './auth.guard';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Get('token')
  async createToken(): Promise<any> {
    return await this.authService.signIn();
  }

  @Get('data')
  @UseGuards(RolesGuard)
  findAll() {
    return { message: 'authed!' };
  }
}

role.guard.ts

Здесь user.request пуст, потому что я никогда не определяю его.Документация не показывает, как и где.

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

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

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user; // it's undefined
    const hasRole = () =>
      user.roles.some(role => !!roles.find(item => item === role));
    return user && user.roles && hasRole();
  }
}

auth.module.ts

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { HttpStrategy } from './http.strategy';
import { UserModule } from './../user/user.module';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';

@Module({
  imports: [
    PassportModule.register({ defaultStrategy: 'jwt' }),
    JwtModule.register({
      secretOrPrivateKey: 'secretKey',
      signOptions: {
        expiresIn: 3600,
      },
    }),
    UserModule,
  ],
  providers: [AuthService, HttpStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

auth.service.ts

import { Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(
    private readonly userService: UserService,
    private readonly jwtService: JwtService,
  ) {}

  async signIn(): Promise<object> {
    // In the real-world app you shouldn't expose this method publicly
    // instead, return a token once you verify user credentials
    const user: any = { email: 'user@email.com' };
    const token: string = this.jwtService.sign(user);
    return { token };
  }

  async validateUser(payload: any): Promise<any> {
    // Validate if token passed along with HTTP request
    // is associated with any registered account in the database
    return await this.userService.findOneByEmail(payload.email);
  }
}

jwt.strategy.ts

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

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

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

Документация: https://docs.nestjs.com/guards

Спасибо за любую помощь.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

В дополнение к вашему RolesGuard вам необходимо использовать AuthGuard.

Стандарт

Вы можете использовать стандартную реализацию AuthGuard, которая присоединяет объект пользователя к запросу.Выдает ошибку 401, когда пользователь не аутентифицирован.

@UseGuards(AuthGuard('jwt'))

Extension

Если вам нужно написать собственную защиту, потому что вам нужно другое поведение, расширьте исходный AuthGuard и переопределитеметоды, которые нужно изменить (handleRequest в примере):

@Injectable()
export class MyAuthGuard extends AuthGuard('jwt') {

  handleRequest(err, user, info: Error) {
    // don't throw 401 error when unauthenticated
    return user;
  }

}

Зачем это нужно?

Если вы посмотрите на исходный код из AuthGuard вы можете видеть, что он присоединяет пользователя к запросу в качестве обратного вызова для метода passport.Если вы не хотите использовать / расширять AuthGuard, вам придется внедрить / скопировать соответствующие части.

const user = await passportFn(
  type || this.options.defaultStrategy,
  options,
  // This is the callback passed to passport. handleRequest returns the user.
  (err, info, user) => this.handleRequest(err, info, user)
);
// Then the user object is attached to the request
// under the default property 'user' which you can change by configuration.
request[options.property || defaultOptions.property] = user;
0 голосов
/ 22 ноября 2018

Работает ли это, если вы используете req.authInfo?

Пока вы не предоставляете пользовательский обратный вызов для метода passport.authenticate, пользовательские данные должны быть прикреплены к объекту запроса, как этот.

req.authInfo должен быть объектом, который вы вернули в validate методе

...