Nest.js bcrypt (hashing)

해싱(Hashing)

해싱은 데이터의 효율적인 저장과 검색을 위해 사용되는 알고리즘입니다. 해시 함수를 사용하여 데이터를 해시 테이블에 저장하고, 동일한 해시 함수를 사용하여 데이터를 나중에 다시 검색할 수 있습니다. 해시 함수는 일정한 길이의 문자열(해시 값)을 생성하므로, 데이터의 길이에 상관없이 항상 일정한 크기의 데이터를 반환합니다.

 

이러한 해싱 작업을 수행하는데 도움을 주는 모듈이 `bcrypt` 입니다. 해당 글에서는 `Next.js`에서 어떻게 해싱을 하는지 알아 보도록 하겠습니다. 

 

 

모듈 설치

npm i bcrypt
npm i -D @types/bcrypt

 

사용하기

해싱을 하는 곳은 대체로 회원가입하는 유저의 비밀번호 입니다. 회원가입시 유저의 비밀번호를 해싱하는 코드를 구현해 보겠습니다. 

 

해싱

 

패스워드를 해싱하는 메소드 

  async hashPassword(password: string): Promise<string> {
    const salt = await bcrypt.genSalt(10);
    return await bcrypt.hash(password, salt);
  }

 

요청에 따라 새로운 유저 객체를 만들어서 `DB`에 저장하는 서비스

  async create(signUpReqDto: SignUpReqDto): Promise<User> {
    await this.validateNewUser(signUpReqDto);

    const hashedPassword = await this.hashPassword(signUpReqDto.password);

    const createdUser = {
      ...signUpReqDto,
      password: hashedPassword,
    };

    return this.userRepository.create(createdUser);
  }

 

 

이제는 테스트를 해보겠습니다. 아래와 같은 객체로 회원가입이 요청이 왔다고 보겠습니다. 

{
  "name": "John Doe",
  "email": "john.doe1@example.com",
  "password": "Securepassword1",
  "passwordConfirmation" : "Securepassword1"
}

 

패스워드가 해싱된 결과는 아래와 같습니다. 패스워드가 객체에서 보낸 값이 아닌 다른 값으로 저장된 것을 볼 수 있습니다. 

{
  "name": "John Doe",
  "email": "john.doe1@example.com",
  "password": "$2b$10$hLUdX6Zvcb95sPWuNpWkVO4x3u0JOByC9Gmtx5mRpHDPCpO9EhOIy",
  "role": "user",
  "_id": "6513deaa347d71fa239bc3de",
  "createdAt": "2023-09-27T07:50:02.189Z",
  "__v": 0
}

 

비교

로그인을 한다고 하면 해싱된 패스워드를 다시 비교하여야 하는 경우가 일 것입니다. 이렇게 바뀐 비밀번호를 어떻게 비교하여 검증하는지 알아보도록 하겠습니다. 

 

아래의 코드는 로그인 시도를 하는 유저의 아이디를 가지고 `DB`에 데이터 존재여부를 확인하고 패스워드가 일치하는지 검증하는 메소드 입니다. 

  async validateUser(email: string, pass: string): Promise<User> {
    const user = await this.userService.findOneByEmail(email);
    if (!user) {
      throw new BadRequestException({
        message: ExceptionMassage.USER_NOT_FOUND,
        at: 'AuthService.validateUser',
      });
    }

    const isMatch = await bcrypt.compare(pass, user.password);

    if (!isMatch) {
      throw new BadRequestException({
        message: ExceptionMassage.PASSWORD_NOT_MATCH,
        at: 'AuthService.validateUser',
      });
    }

    return user;
  }

 

성공적으로 검증이 되었다면 유저에게 토큰을 제공하여 마무리 해줍니다. 

  async signIn(signInReqDto: SignInReqDto): Promise<SignInResDto> {
    const validUser = await this.validateUser(
      signInReqDto.email,
      signInReqDto.password,
    );

    const { access_token } = await this.createToken(validUser);
    return new SignInResDto(access_token);
  }

 

'Backend > Nest.js' 카테고리의 다른 글

Nest.js Rate Limiting 설정  (0) 2023.09.30
Nest.js Swagger 보안 설정  (0) 2023.09.30
Nest.js Module  (0) 2023.09.26
Nest.js Provider  (0) 2023.09.26
Nest.js Swagger Bearer 인증 적용  (1) 2023.09.26