저장을 습관화
NestJS - 회원 가입 API 개발시 패스워드 암호화하기, mongoose virtual field 사용하기 본문
준비물 - bcrypt, @types/bcrypt
$ npm install bcrypt
$ npm install -D @types/bcrypt
서비스 파일
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { CatRequestDto } from './dto/cats.request.dto';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Cat } from './cats.schema';
import * as bcrypt from 'bcrypt';
@Injectable()
export class CatsService {
constructor(@InjectModel(Cat.name) private readonly catModel: Model<Cat>) {}
async signUp(body: CatRequestDto) {
const { email, name, password } = body;
const isCatExist = await this.catModel.exists({ email });
// 이미 존재하는 이메일일 경우 에러처리
if (isCatExist) {
throw new UnauthorizedException('해당하는 고양이는 이미 존재합니다.');
// 위 방법과 아래 방법은 동일한 기능을 한다.
// throw new HttpException('해당하는 고양이는 이미 존재합니다.', 403);
}
// 패스워드 암호화
const hashedPassword = await bcrypt.hash(password, 10);
// DB에 저장
const cat = await this.catModel.create({
email: email,
name: name,
password: hashedPassword,
});
return cat;
}
}
스키마 파일
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { SchemaOptions, Document } from 'mongoose';
const options: SchemaOptions = {
timestamps: true, // DB에 데이터가 만들어질때 타임스탬프를 찍는다
};
@Schema(options)
export class Cat extends Document {
@Prop({
required: true,
unique: true,
})
@IsEmail()
@IsNotEmpty()
email: string;
@Prop({
required: true,
})
@IsString()
@IsNotEmpty()
name: string;
@Prop({
required: true,
})
@IsString()
@IsNotEmpty()
password: string;
@Prop()
@IsString()
imgUrl: string;
readonly readOnlyData: { id: string; email: string; name: string };
}
export const CatSchema = SchemaFactory.createForClass(Cat);
// postman 등에서 회원가입 API를 사용하였을때
// 암호화된 패스워드가 노출되는 것을 막는 방법
// mongoose에서 지원해주는 virtual field를 사용한다.
// virtual field는 실제로 DB에 저장되는 field는 아니지만
// 개발자가 비즈니스 로직에서 사용할 수 있는 field이다.
// 스키마에 virtual 메소드를 사용한다
// readOnlyData: 클라이언트에게 보여줄 데이터만 가상으로 필터링해서 나간다
CatSchema.virtual('readOnlyData').get(function (this: Cat) {
return {
id: this.id,
email: this.email,
name: this.name,
};
});
Virtual Filed는 실제로 DB에 저장되는 filed 내용은 아니지만, 개발자가 비즈니스 로직에 사용할 수 있는 filed이다.
사용 전
"data": {
"email": "fourthTest@email.com",
"name": "fourth",
"password": "$2b$10$0fWqIwT6Yazo54tPR0zxP.3BQV7oN1lx2YaoJKVd//lwngWMwVJcS",
"_id": "651abd06a76166673177cdfb",
"createdAt": "2023-10-02T12:52:22.805Z",
"updatedAt": "2023-10-02T12:52:22.805Z",
"__v": 0
}
body를 통해 전송한 데이터와 함께 DB에 저장된 데이터가 모두 보이게 된다.
패스워드가 암호화 된 상태이지만, 이 조차도 노출되지 않도록 할 수 있다.
virtual field 사용 후
서비스 파일 수정
// 생략
@Injectable()
export class CatsService {
constructor(@InjectModel(Cat.name) private readonly catModel: Model<Cat>) {}
async signUp(body: CatRequestDto) {
// 생략
return cat.readOnlyData; // 서비스의 반환값 cat에서
// 스키마에서 설정했던 virtual filed 'readOnlyData'을 골라 반환하도록 한다
}
}
"data": {
"id": "651ac06bd1d8997139ea674b",
"email": "fifthTest@email.com",
"name": "fifth"
}
virtual field에서 지정한 id, email, name만이 반환되어 사용자에게 노출되는 모습을 확인할 수 있다.
'공부 > node.js' 카테고리의 다른 글
NestJS - multer를 이용한 미디어 파일 서비스 (0) | 2023.10.09 |
---|---|
NestJS - Swagger를 사용해서 API 문서 만들기 (0) | 2023.10.04 |
에러 기록 - export class Cat extends Document... ReferenceError: Document is not defined (0) | 2023.10.02 |
NestJS - .env (0) | 2023.10.01 |
NestJS - mongoose 사용 시 useNewUrlParser 옵션 설정 (0) | 2023.09.30 |