개발일지
[NestJS] 로그인 구현 #1 - 유효성 검증 본문
로그인 요구사항
- 이메일, 비밀번호를 입력받습니다.
- 유효성 검사
- 각 필드 빈칸 체크
- 이메일 가입 여부 확인
- 비밀번호 일치 확인
- 인증 방식으로 jwt를 사용합니다.
- 로그인 시 access token, refresh token 발급
- access token 기한 만료 시 재발급
Modeling
refresh token 검증 시 db에 저장된 refresh token 값과의 일치 여부를 확인할 계획입니다. refresh token을 관리할 RefreshTokens를 생성해줍니다. Users와 일대일 관계를 가집니다.
# users.prisma
model RefreshTokens {
token String @unique
user Users @relation(fields: [userId], references: [id])
userId Int @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("refresh-tokens")
}
model Users {
...
refreshToken RefreshTokens?
}
DTO
로그인 시 입력받을 데이터에 대한 dto를 생성합니다.
export class SignInUserDto {
@IsEmail()
@IsNotEmpty()
email: string;
@IsNotEmpty()
password: string;
}
SignIn 유효성 검증
signIn의 전반적인 로직은 다음과 같습니다.
// users/users.service.ts
async signIn(data: SignInUserDto): Promise<SignIn> {
// 1-1. 유효성 검사 - 가입 여부 확인
// 1-2. 유효성 검사 - 비밀번호 일치 여부 확인
// 2. 토큰 생성
...
가입 여부 확인
해당 이메일로 가입한 유저가 존재하는 지 확인해야합니다. 전에 만들어놨던 findUserByWhereOption
메소드를 사용합니다. where 조건으로 email을 사용하기위해 WhereOptionByUserEmail를 정의하고 WhereOption으로 추가합니다.
// common/interface/users.interface.ts
export type WhereOptionByUserEmail = {
email: string;
};
export type WhereOption =
| WhereOptionByUserId
| WhereOptionByUserEmail
| WhereOptionByUserNickName;
구현한 내용은 다음과 같습니다. 유저가 존재하지 않을 경우 error를 반환합니다.
async signIn(data: SignInUserDto): Promise<SignIn> {
// 1-1. 유효성 검사 - 가입 여부 확인
const whereOption: WhereOptionByUserEmail = {
email: data.email,
};
const user: Users = await this.usersRepository.findUserByWhereOption(
whereOption,
);
if (!user) {
throw new CustomException(UsersException.USER_NOT_EXIST);
}
// 1-2. 유효성 검사 - 비밀번호 일치 여부 확인
// 2. 토큰 생성
}
비밀번호 일치 여부 확인
async signIn(data: SignInUserDto): Promise<SignIn> {
// 1-1. 유효성 검사 - 가입 여부 확인
...
// 1-2. 유효성 검사 - 비밀번호 일치 여부 확인
await this._validatePassword(data.password, user.password, 'signIn');
// 2. 토큰 생성
}
회원가입에서 사용한 _validatePassword
메소드를 사용했습니다.
// 원래의 _validatePassword
private _validatePassword(password: string, checkPassword: string) {
if (password !== checkPassword) {
throw new CustomException(UsersException.NOT_MATCHED_PASSWORD);
}
}
signIn, signUp을 구분하기 위한 파라미터 type을 추가하고 조건문으로 처리합니다. 비밀번호는 db에 암호화되어 저장되기 때문에 bcrypt.compare()
로 비교해야합니다.
// 수정된 _validatePassword
private async _validatePassword(
password: string,
checkPassword: string,
type: ValidatePasswordType = 'signUp',
) {
if (type == 'signUp' && password !== checkPassword) {
throw new CustomException(UsersException.NOT_MATCHED_PASSWORD);
}
if (type == 'signIn' && !(await bcrypt.compare(password, checkPassword))) {
throw new CustomException(UsersException.NOT_MATCHED_PASSWORD);
}
}
'NestJS, Node.js > #01 Project - 투표 커뮤니티' 카테고리의 다른 글
[NestJS] Custom decorators (0) | 2022.10.28 |
---|---|
[NestJS] 로그인 구현 #2 - Passport, JWT (0) | 2022.10.27 |
[NestJS] 회원가입 구현 #2 - 유효성 검증 (0) | 2022.10.27 |
[NestJS] 회원가입 구현 #1 - Pipe 적용 (0) | 2022.10.27 |
[NestJS] 예외 처리와 exception filter (0) | 2022.10.27 |