개발일지

[NestJS] 로그아웃 및 비밀번호 재설정 본문

NestJS, Node.js/#01 Project - 투표 커뮤니티

[NestJS] 로그아웃 및 비밀번호 재설정

lyjin 2022. 11. 14.

로그아웃

플로우

제가 생각한 로그아웃 플로우는 다음과 같습니다.

  1. 클라이언트에서 로그아웃 api를 요청합니다.
  2. DB에 저장된 refresh token을 삭제한 후 결과를 response 합니다.
  3. 삭제 성공일 경우, 헤더에 있는 access token을 제거합니다.

 

 

구현

// auth/auth.controller.ts

@Delete('sign-out')
async signOut() {
  const userId = 1;
  const data: SignOutUserDto = {
    userId,
  };

  return await this.authService.signOut(data);
}

 

// auth/auth.service.ts

async signOut(data: SignOutUserDto) {
  return await this.usersRepository.deleteRefreshToken(data.userId);
}

 

// auth/auth.repository.ts

async deleteRefreshToken(userId: number) {
  await this.prisma.refreshTokens.delete({
    where: {
      userId,
    },
  });
}

 

 


비밀번호 재설정

유틸리티 타입 PickType, Omit을 사용하여 dto를 정의했습니다.

 

// auth/auth.controller.ts

  @Patch('reset/password')
  async resetPassword(@Body() body: Omit<ResetPasswordDto, 'userId'>) {
    const userId = 1;

    const data: ResetPasswordDto = {
      ...body,
      userId,
    };

    return await this.authService.resetPassword(data);
  }

 

export class ResetPasswordDto extends PickType(SignUpUserDto, [
  'password',
  'checkPassword',
]) {
  userId: number;
}

 

디스트럭쳐링하여 객체 값들을 변수로 저장했습니다. { password: currPassword } 는 변수명 password를 currPassword로 재정의합니다. 변경하려는 비밀번호가 현재 비밀번호와 동일하거나 password와 checkPassword가 일치하지 않으면 에러를 던집니다.

 

 async resetPassword(data: ResetPasswordDto) {
    const { userId, password, checkPassword } = data;

    const { password: currPassword } =
      await this.usersRepository.findUserByWhereOption({
        id: userId,
      });

    if (await bcrypt.compare(password, currPassword)) {
      throw new CustomException(UsersException.SAME_CURR_PASSWORD);
    }
    await this._validatePassword(password, checkPassword);

    return await this.usersRepository.updatePassword(userId, password);
  }

 

 

변경하려는 비밀번호를 암호화하여 업데이트합니다.

 

// users/users.repository.ts

  async updatePassword(userId: number, password: string) {
    return await this.prisma.users.update({
      where: {
        id: userId,
      },
      data: {
        password: await bcrypt.hash(password, 10),
      },
    });
  }

 

 


ValidatePasswordType 변경

ValidatePasswordType'signUp' | 'signIn'처럼 서비스 단위로 정의하니 다른 서비스에서 사용될 때마다 타입을 추가해줘야하는 번거로움이 생깁니다.


이를 '암호화 된 데이터와 비교할 경우', '암호화되지 않은 데이터와 비교할 경우'의 기준으로 변경했습니다.

 

// 변경 전
type ValidatePasswordType = 'signUp' | 'signIn';

// 변경 후
type ValidatePasswordType = 'clearPassword' | 'hashedPassword';

private async _validatePassword(
  password: string,
  checkPassword: string,
  type: ValidatePasswordType = 'clearPassword',
) {
  if (type == 'clearPassword' && password !== checkPassword) {...}

  if (type == 'hashedPassword' && !(await bcrypt.compare(password, checkPassword))
  ) { ...}