인증관련부분은 다음시간에 구현하고, 먼저 회원가입과 로그인기능에 대해 구현해보겠습니다.
auth와 user 파일을 간단하게 생성
nest g resource auth
nest g resource user
user
[ user/entities/user.entitiy.ts ]
import {
BeforeInsert,
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
import * as bcrypt from 'bcrypt';
@Entity({ name: 'user' })
export class UserEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
email: string;
@Column()
password: string;
@Column()
nickname: string;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
@DeleteDateColumn()
deleted_at: Date;
@BeforeInsert()
private beforeInsert() {
this.password = bcrypt.hashSync(this.password, 10);
}
}
@BeforeInsert() 데코레이터는 TypeORM에서 제공하는 데코레이터 중 하나이며, 데이터베이스에 새로운 엔티티가 저장되기 전에 자동으로 실행되는 메서드를 정의할 수 있습니다.
bcrypt.hashSync() 함수는 bcrypt 라이브러리에서 제공하는 함수 중 하나로, 주어진 문자열을 해시화하여 반환합니다. 이 함수는 동기식으로 작동하므로, 해시화 작업이 완료될 때까지 대기합니다.
[ user/user.service.ts ]
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from 'src/user/entities/user.entity';
import { AuthDTO } from 'src/auth/dto/authDto';
@Injectable()
export class UserService {
constructor(
@InjectRepository(UserEntity)
private userRepository: Repository<UserEntity>,
) { }
async create(authDTO: AuthDTO.SignUp) {
const userEntity = await this.userRepository.create(authDTO);
return await this.userRepository.save(userEntity);
}
async findById(id: number) {
return await this.userRepository.findOne({
where: {
id,
},
});
}
async findByEmail(email: string) {
return await this.userRepository.findOne({
where: {
email,
},
});
}
async findByNickname(nickname: string) {
return await this.userRepository.findOne({
where: {
nickname,
},
});
}
}
[ user/user.controller.ts ]
import {
Body,
ConflictException,
Controller, Post,
} from '@nestjs/common';
import { UserService } from './user.service';
import { AuthDTO } from 'src/auth/dto/authDto';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) { }
@Post('/signup')
async signup(@Body() authDTO: AuthDTO.SignUp) {
const { email, nickname } = authDTO;
const hasEmail = await this.userService.findByEmail(email);
if (hasEmail) {
throw new ConflictException('이미 사용중인 이메일 입니다.');
}
const hasNickname = await this.userService.findByNickname(nickname);
if (hasNickname) {
throw new ConflictException('이미 사용중인 닉네임 입니다.');
}
const userEntity = await this.userService.create(authDTO);
return '회원가입성공';
}
}
회원가입코드는 user crud와 관련된것이기 때문에 userController에서 작성해주었습니다.
throw error를 controller에서 처리하는 이유는, controller는 API 엔드포인트와 직접적으로 연결되어 있어서 클라이언트에게 에러 메시지를 응답으로 반환할 수 있기 때문입니다.
반면에, throw error를 service나 다른 모듈에서 처리하게 되면, 이 에러를 controller에서 캐치할 수 없기 때문에 클라이언트에게 적절한 응답을 보내줄 수 없습니다. 따라서 일반적으로 throw error는 controller에서 처리하는 것이 좋습니다.
[ user/user.module.ts ]
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { UserEntity } from './entities/user.entity';
@Module({
imports: [TypeOrmModule.forFeature([UserEntity])], //userrepository사용할수있도록 주입
exports: [UserService], //userService 다른곳에서 사용할수 있도록 exports
controllers: [UserController],
providers: [UserService],
})
export class UserModule {}
auth
인증에 관련한 것들은 auth에서 구현하였습니다.
[ auth/dto/authDto.ts ]
import { IsEmail,IsString ,Length} from "class-validator";
export namespace AuthDTO {
export class SignUp {
@IsEmail()
email: string;
@IsString()
@Length(4, 20)
password: string;
@IsString()
nickname: string;
}
export class SignIn {
@IsEmail()
email: string;
@IsString()
@Length(4, 20)
password: string;
}
}
[ auth/auth.controller.ts ]
import {
Controller,
Post,
Body,
Get,
Req,
UseGuards,
UnauthorizedException
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt/dist';
import * as bcrypt from 'bcrypt';
import { AuthDTO } from './dto/authDto';
import { UserService } from 'src/user/user.service';
@Controller()
export class AuthController {
constructor(private readonly userService: UserService) { }
@Post('/signin')
async signin(@Body() authDTO: AuthDTO.SignIn) {
const { email, password } = authDTO;
const user = await this.userService.findByEmail(email);
if (!user) {
throw new UnauthorizedException('이메일 또는 비밀번호를 확인해 주세요.');
}
const isSamePassword = bcrypt.compareSync(password, user.password);
if (!isSamePassword) {
throw new UnauthorizedException('이메일 또는 비밀번호를 확인해 주세요.');
}
return "로그인 완료"
}
}
bcrypt.compareSync() 함수는 bcrypt 라이브러리에서 제공하는 함수 중 하나로, 주어진 문자열과 해시화된 문자열을 비교하여 일치 여부를 반환합니다. 이 함수는 동기식으로 작동하므로, 비교 작업이 완료될 때까지 대기합니다.
[ auth.module.ts ]
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserModule } from 'src/user/user.module';
@Module({
imports: [UserModule],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}
app
[ app.module.ts ]
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { UserModule } from './user/user.module';
import { UserEntity } from './user/entities/user.entity';
@Module({
imports: [
ConfigModule.forRoot(),
TypeOrmModule.forRoot({
type: 'mysql',
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: [`${__dirname}/**/entities/*.entity.{ts,js}`],
synchronize: Boolean(process.env.DB_SYNC),
}),
AuthModule,
UserModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
테스트
[ 회원가입 ]
[ 로그인 ]
[ mysql ]
다음시간에는 jwt 토큰 인증을 붙여보겠습니다!
user에서 crud 하는것은 userController에 작성하고 user인증하는 부분은 authController에 작성하였습니다.
'nest js' 카테고리의 다른 글
NestJs JWT 토큰 생성 / 토큰 인증(Guard) (2) | 2023.04.14 |
---|---|
NestJs에서 환경변수 (0) | 2023.04.13 |
NestJs 데이터베이스 연동하기 (mysql, typeorm) (0) | 2023.04.12 |
NestJs 프로젝트에서 Swagger 사용하기 (0) | 2023.04.07 |
NestJs Guard에 대해 알아보자 (0) | 2023.04.07 |