Сериализация: как исключить столбцы Entity в ответе json, но не внутренние запросы в Nestjs

Изменить:
Я просмотрел этот вопрос / ответ Как исключить поле сущности из json-контроллера
Но, как показано ниже, это исключает это поле из всех запросов (в порнт, где когда пытаясь обработать проверку пользователя, поле пароля исключается с помощью запроса репозитория findOne в методе маршрута / контроллера, у которого нет ClassSerializerInterceptor

У меня есть объект в nest.js / typeorm; Я пытаюсь исключить поле пароля из возвращенного json, но не исключать поле пароля из любых запросов репозитория в моей службе. Например:

user.entity.ts:

import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, 
UpdateDateColumn, ManyToOne } from 'typeorm';
import { Exclude } from 'class-transformer';
import { Account } from '../accounts/account.entity';

@Entity()
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({
    unique: true,
  })
  email: string;

 @Column()
 password: string;
}

auth.controller.ts:

import { Controller, Post, Body, Request, Req, Get, UseInterceptors, ClassSerializerInterceptor, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { IUserRequest } from '../../interfaces/user-request.interface';

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

  @Post('/login')
  async login(@Request() req: Request) {
    const user = await this.authService.checkCredentials(req.body);
    return this.authService.logUserIn(user.id);
  }

  @Get('/profile')
  @UseGuards(AuthGuard())
  @UseInterceptors(ClassSerializerInterceptor)
  async profile(@Request() req: IUserRequest) {
    const profile = await this.authService.getLoggedInProfile(req.user.id);
    return { profile };
  }
}

Если я добавлю Exclude() к паролю вот так

@Exclude()
@Column()
password: string;

пароль включен в ответ

Если я удалю Column() из пароля,

@Exclude()
password: string;

Пароль исключается из ответа и всех внутренних запросов, таких как:

const user = await this.userRepository.findOne({ where: { id }, relations: ['account']});

Возможно ли это в nest.js с использованием ClassSerializerInterceptor?

Если так, был бы признателен за указатель в правильном направлении.


person RWest    schedule 23.01.2019    source источник


Ответы (2)


Вы можете пропустить свойства в зависимости от операции < / а>. В вашем случае вы должны использовать:

@Column()
@Exclude({ toPlainOnly: true })
password: string;

Это означает, что пароль пропускается только тогда, когда класс преобразуется в json (когда вы отправляете ответ), а не когда json преобразуется в класс (когда вы получаете запрос).

Затем добавьте @UseInterceptors(ClassSerializerInterceptor) в свой контроллер или метод контроллера. Это автоматически преобразует класс сущности в json, когда вы его вернете.


Чтобы ClassSerializerInterceptor работал, сначала убедитесь, что ваша сущность была преобразована в класс. Это можно сделать автоматически, используя ValidationPipe с параметром { transform: true} или вернув объект из репозитория (базы данных). Также вам нужно вернуть сам объект:

@Post()
@UseInterceptors(ClassSerializerInterceptor)
addUser(@Body(new ValidationPipe({transform: true})) user: User) {
  // Logs user with password
  console.log(user);
  // Returns user as JSON without password
  return user;
  }

В противном случае вам придется преобразовать его вручную:

async profile(@Request() req: IUserRequest) {
  // Profile comes from the database so it will be an entity class instance already
  const profile = await this.authService.getLoggedInProfile(req.user.id);
  // Since we are not returning the entity directly, we have to transform it manually
  return { profile: plainToClass(profile) };
}
person Kim Kern    schedule 23.01.2019
comment
Спасибо за Ваш ответ. К сожалению, по какой-то причине это все еще не работало с @UseInterceptors (ClassSerializerInterceptor). Однако добавление преобразования класса @TransformClassToPlain () помогло - person RWest; 24.01.2019
comment
Ах, я только что увидел, что вы не возвращаете объект напрямую. ClassSerializerInterceptor будет работать, только если будет возвращена сама сущность, поэтому return profile вместо return {profile}. Если вы не возвращаете его напрямую, вам нужно вручную преобразовать его с помощью plainToClass(). - person Kim Kern; 24.01.2019

Я бы посоветовал также посмотреть на скрытые столбцы TypeOrm. Здесь у вас @Column({select: false}) на столбец пароля, все запросы, использующие стандартный поиск или запрос, будут исключать столбец пароля.

import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";

@Entity()
export class User {

@PrimaryGeneratedColumn()
id: number;

@Column()
name: string;

@Column({select: false})
password: string;
}

Затем во время проверок / случаев, когда вам нужен пароль, который вы делаете

const users = await connection.getRepository(User)
.createQueryBuilder()
.select("user.id", "id")
.addSelect("user.password")
.getMany();
person Nelson Bwogora    schedule 24.03.2020