Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 454 Vote(s) - 3.54 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to exclude entity field from returned by controller JSON. NestJS + Typeorm

#1
I want to exclude password field from returned JSON.
I am using NestJS and Typeorm.

The solution provided on [this question][1] doesn't work for me or in NestJS. I can post my code if needed.
Any other ideas or solutions? Thanks.


[1]:

[To see links please register here]

Reply

#2
You can use the package

[To see links please register here]


You can exclude a properties using decorators and also, you can exlude properties using groups.
Reply

#3
I'd suggest creating an interceptor that takes advantage of the [class-transformer](

[To see links please register here]

) library:

@Injectable()
export class TransformInterceptor implements NestInterceptor {
intercept(
context: ExecutionContext,
call$: Observable<any>,
): Observable<any> {
return call$.pipe(map(data => classToPlain(data)));
}
}

Then, simply exclude properties using `@Exclude()` decorator, for example:

import { Exclude } from 'class-transformer';

export class User {
id: number;
email: string;

@Exclude()
password: string;
}
Reply

#4
You can overwrite the toJSON method of the model like this.

```typescript
@Entity()
export class User extends BaseAbstractEntity implements IUser {
static passwordMinLength: number = 7;

@ApiModelProperty({ example: faker.internet.email() })
@IsEmail()
@Column({ unique: true })
email: string;

@IsOptional()
@IsString()
@MinLength(User.passwordMinLength)
@Exclude({ toPlainOnly: true })
@Column({ select: false })
password: string;

@IsOptional()
@IsString()
@Exclude({ toPlainOnly: true })
@Column({ select: false })
passwordSalt: string;

toJSON() {
return classToPlain(this);
}

validatePassword(password: string) {
if (!this.password || !this.passwordSalt) {
return false;
}
return comparedToHashed(password, this.password, this.passwordSalt);
}
}
```

By using the class-transformer method of plainToClass along with the **@Exclude({ toPlainOnly: true })**, the password will be excluded from the JSON response, but will be available in the model instance. I like this solution because it keeps all the model configuration in the entity.
Reply

#5
As an addition to [Kamil's answer][1]:

Instead of creating your own interceptor, you can now use the built-in `ClassSerializerInterceptor`, see the [serialization docs][2].

@UseInterceptors(ClassSerializerInterceptor)

You can use it on a controller class or its individual methods. Each entity returned by such a method will be transformed with class-transformer and hence take the `@Exclude` annotations into account:

```
import { Exclude } from 'class-transformer';

export class User {
/** other properties */

@Exclude()
password: string;
}
```
<hr>

You can customize its behavior by defining `@SerializeOptions()` on your controller or its methods:

@SerializeOptions({
excludePrefixes: ['_'],
groups: ['admin']
})

to, for example, expose certain fields only to certain users:

```
@Expose({ groups: ["admin"] })
adminInfo: string;
```
[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#6
@Column({ select: false })
password: string

Can read about hidden columns [here][1]


[1]:

[To see links please register here]

Reply

#7
Lots of good answers in this thread. To build on apun's answer above, I think the following approach is the least likely to accidentally leak a password field:

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

If the entity doesn't select that field by default, and it can only be explicitly queried (e.g. via `addSelect()` if using the query builder), I think it is a lot less likely that there's a slip somewhere, and there's less reliance on the "magic" of a framework (which is ultimately the `class-transformer` library) to ensure security. Realistically in many projects the only place you'd explicitly select it is where you check credentials.

This approach can also help keep the password hash from accidentally leaking into log entries, etc, which is a consideration that hasn't been mentioned yet. It feels much safer to toss around the user object knowing that it doesn't include sensitive information, especially if it could end up serialized in a log entry somewhere.

All said, the documented approach for NestJS is to use the `@Exclude()` decorator and the accepted answer is from the project's founder.

I definitely make frequent use of the `Exclude()` decorator, but not necessarily for password or salt fields.
Reply

#8
This is already an old topic, but I still would like to share my solution, maybe it will help somebody. I use Express, but my example is probably suitable for this case as well.

So in your entity class you just define an additional static `removePassword()` method, which receives an instance of entity itself, and you send an object created by this method instead of original entity object you got from DB:
```typescript
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity({ name: 'users' })
export class User {
@PrimaryGeneratedColumn('uuid')
id: string | undefined;

@Column({ type: 'varchar', length: 100, unique: true })
email: string | undefined;

@Column({ type: 'text' })
password: string | undefined;

static removePassword(userObj: User) {
return Object.fromEntries(
Object.entries(userObj).filter(([key, val]) => key !== 'password')
);
}
}
```
This is basically like calling a `filter()` method on an array, but slightly more complicated: you create a new object (the one you'll send eventually) from entries array, produced by filtering out a password entry from original entries array (with this exact `filter()` method).

In your route handlers though you'll just always do something like this:
```typescript
import { Router, Request, Response, NextFunction } from 'express';
import { User } from '../../entity/User';
import { getRepository } from 'typeorm';

const router = Router();

router.post(
'/api/users/signin',
(req: Request, res: Response, next: NextFunction) => {
const { email } = req.body;

getRepository(User)
.findOne({ email })
.then(user =>
user ? res.send(User.removePassword(user)) : res.send('No such user:(')
)
.catch(err => next(new Error(err.message)));
}
);

export { router as signinRouter };
```
You may also use regular method:
```typescript
withoutPassword() {
return Object.fromEntries(
Object.entries(this).filter(([key, val]) => key !== 'password')
);
}
```
and in your route handler:
```typescript
res.send(user.withoutPassword());
```
Reply

#9
To avoid any back-pain and headaches,
I would suggest using the `plainToClass` to have a full mongoose/class-transform compatibility and avoid having to make custom overrides to overcome this isse.

Example, add this in your service :

```
async validateUser(email: string, password: string): Promise<UserWithoutPassword | null> {
const user = await this.usersService.findOne({ email });

if (user && await compare(password, user.password))
{
return plainToClass(UserWithoutPassword, user.toObject());
}

return null;
}

```

Source : [Stackoverflow answer][1]


[1]:

[To see links please register here]

Reply

#10
what simply worked for me was just

annotating the field with @Exclude and overiding toJSON model method like so

`toJSON() {
return classToPlain(this);
}`
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through