인프런 커뮤니티 질문&답변

zeler1004님의 프로필 이미지
zeler1004

작성한 질문수

[코드캠프] 부트캠프에서 만든 고농축 백엔드 코스

11-03 회원 조회 API - 인가

로그인한 user의 비밀번호를 변경하는 API updateUserPwd 로직

해결된 질문

작성

·

939

·

수정됨

0

 quiz19 -2 에서

토큰기반인증(로그인)된 유저의 비밀번호 변경 로직을 구현하고 있는데요..

resolver와 service의 연결부분에서 에러가 발생하는데 혼자서 해결이 어려워 문의드립니다.

제가 생각한 updateUserPwd의 로직은

  1. 유저가 있는지의 여부 확인

  2. 비밀번호의 일치 여부 확인

  3. bcrypt로 변경하고자하는 비밀번호의 암호화

  4. 암호화된 변경비밀번호를 해당하는 email의 DB에 저장

이렇게 하면 끝나는 로직이라고 생각하고 소스코드를 작성했습니다. 1차적으로 제가 생각한 로직에 빠진 부분이 있는지 궁금하고 지금의 소스코드로 어떤부분을 보완해야하는지 궁금합니다.(현재 코드블록으로 공유한 내용은 users.service.ts에서 return부분에 where에서 에러가 발생하는 상황입니다..)스크린샷 2023-06-16 오후 5.02.12.png

 

 

추가로 필요한 정보나 내용, 소스코드가 있으면 추가적으로 공유하도록 하겠습니다. 도와주세요~~~

나머지 import해온 class들은 수업을 통해서 그대로 가져온 내용들입니다.

//users.resolver.ts

@UseGuards(gqlAuthAccessToken)
  @Mutation(() => String)
  updateUserPwd(
    @Args('email') email: string,
    @Args('password') password: string,
  ): string {
    this.usersService.updateUserPwd({ email, password });
    return '비밀번호 수정 성공';
  }
//users.service.ts

async updateUserPwd({
    email,
    password,
  }: IUserServiceUpdateUserPwd): Promise<UpdateResult> {
    const user = await this.findOneByEmail({ email });
    if (!user)
      throw new UnprocessableEntityException('등록되지 않은 이메일 입니다.');

    const isAuth = await bcrypt.compare(password, user.password);
    if (!isAuth) throw new UnprocessableEntityException('틀린 암호입니다.');

    const hashedPassword = await bcrypt.hash(
      password,
      Number(process.env.SALT),
    );
    return this.UsersRepository.update(
      { password: hashedPassword },
      {
        where: { email: user.email },
      },
    );
  }

답변 1

0

노원두님의 프로필 이미지
노원두
지식공유자

안녕하세요! zeler1004님!

먼저, 보내주신 코드에서 보완되면 좋을 부분을 말씀드릴게요!

image

다음으로, 에러메시지와 관련하여서는 아래 그림을 참고해 주세요!^^
image

zeler1004님의 프로필 이미지
zeler1004
질문자

선생님!

조언주신데로 일부 수정을 했습니다!

생각해보면 update함수는 자동으로 where절을 넣어줄 수 있는 기능이 있는데 그걸 제가 놓치고 매몰되어있던것 같습니다.

그리고 userUpdatePwd 진행할때는 user에 대한 accessToken이 발행되고 나면 비밀번호에 대해서는 따로 bcrypt의 compare 메소드를 사용할 필요가 없는게 맞는걸까요?!

 

resolver 부분에서 비동기화 시키는 부분은 이해가 됐습니다 !

service부분 코드내용만 봐주실 수 있을까요?! 여기서 더 개선해야하거나 디벨롭시키면 좋을만한 부분이 있으면 조언주시면 감사하겠습니다!

  
//users.service.ts

  async updateUserPwd({
    email,
    password,
  }: IUserServiceUpdateUserPwd): Promise<UpdateResult> {
    const user = await this.findOneByEmail({ email });
    if (!user)
      throw new UnprocessableEntityException('등록되지 않은 이메일 입니다.');

    // resolver에서 useGuard를 사용하여 accessToken을 발행하기 때문에 해당된 유저만 접근가능하여 bcrypt.compare는 필요하지 않음.
    // const isAuth = await bcrypt.compare(password, user.password);
    // if (!isAuth) throw new UnprocessableEntityException('틀린 암호입니다.');

    const hashedPassword = await bcrypt.hash(
      password,
      Number(process.env.SALT),
    );
    return await this.UsersRepository.update(
      { email: user.email },
      { password: hashedPassword },
    );
  }

service부분 코드블록입니다.

 

우선 위의 코드방식으로 작성해서 테스트했더니 비밀번호는 hash된 비밀번호로 변경이 된 것을 DB에서 확인했습니다.

스크린샷 2023-06-20 오후 2.09.13.png

 

많이 바쁘시겠지만 확인해주시면 감사하겠습니다 🙇🏻‍♂️

노원두님의 프로필 이미지
노원두
지식공유자

네! 정말 열심히 하고 계시는군요! ㅎㅎ

  1. 우선 1번 질문의 경우는, 서비스 기획에 따라 달라질 수 있어요! 기획상 이전 비밀번호를 확인하고, 비밀번호 변경을 해야한다면, 앞서 한 번 compare를 해야하고, 그렇지 않은 경우는 지금과 같이 하시면 될 것 같아요!

  1. 다음으로 두번째 질문은 수업에서 배운대로 잘 적용을 하신 것 같아요!

     

    하지만, 프로그래밍에는 정답은 없기때문에 더욱 업그레이드를 위한 팁을 질문하신 거라면, 추후 강의를 모두 수강하시고 난 다음에 bcrypt로 hash, compare 하는 로직만 따로 class로 빼서 의존성 주입받아 사용하면 더욱 유지보수 좋은 코드가 될 수 있을 것 같아요!^^

     

    그렇게 해야, 나중에 회원가입, 비밀번호변경 등 여러군데서 사용하는 보안 설정을 한방에 바꿀 수 있겠죠?!

     

zeler1004님의 프로필 이미지
zeler1004

작성한 질문수

질문하기