배포한 프로젝트 유저 피드백 받기

김혁준·2023년 7월 5일
0

django

목록 보기
14/18

피드백 내용 대부분이 프론트 부분이라 따로 정리해야겠다. 그중에 한 가지 백엔드 관련된 피드백이 있었다.

유저가 비밀번호를 모르면 이메일 인증을 통해 비밀번호를 재설정하게 만들어주는 기능이 있었는데, 다른사람이 포스트맨같은 프로그램으로 요청을 하면 요청이 받아들여지는 오류가 있었다. 이는 비밀번호를 모르니까 로그인 안해도 요청이 되게끔 처리했었는데, 그 틈에 오류가 있었던 것이었다. 진짜 사용자인지 아니면 다른사람인지 걸러내는 과정이 필요했다.

해결방안 : url에 쿼리파라미터를 추가한다. 그 후 사용자가 쿼리파라미터를 올바르게 보냈으면 요청을 정상적으로 처리하고 아니면 바로 에러를 띄운다.

class UserResetPasswordPermitView(APIView):
    def get(self, request, uidb64, token):
        try:
            uid = force_str(urlsafe_base64_decode(uidb64))
            user = User.objects.get(pk=uid)
            if account_activation_token.check_token(user, token):
                return redirect(
                    f"{settings.FRONT_BASE_URL}/users/password_change.html?uid={uid}&uidb64={uidb64}&token={token}"
                )
            return Response({"error": "AUTH_FAIL"}, status=status.HTTP_400_BAD_REQUEST)
        except KeyError:
            return Response({"error": "KEY_ERROR"}, status=status.HTTP_400_BAD_REQUEST)
            

위의 클래스는 유저가 인증 이메일을 클릭했을때 실행되는 view이고 f"{settings.FRONT_BASE_URL}/users/password_change.html"로 리다이렉트 시켰었다. 여기에 이메일을 누른 사람만 얻을 수 있는 token과 uidb64를 쿼리파라미터로 추가했다.

return redirect(
                    f"{settings.FRONT_BASE_URL}/users/password_change.html?uid={uid}&uidb64={uidb64}&token={token}"
                    

그 후 패스워드 변경 페이지에는 token과 uidb64가 포함되어있고, 비밀번호 변경을 요청할때 token과 uidb64가 잘못되면 에러를 띄우게 비밀번호 변경을 처리하는 view를 바꿨다.

if not uidb64 or not token:
              return Response({"error": "잘못된 접근입니다!"}, status=status.HTTP_403_FORBIDDEN)
              

token과 uidb64가 없으면 유저가 아니므로(포스트맨 등으로 다른사람이 보낸 요청이므로)
에러를 띄운다.

 if account_activation_token.check_token(user, token):
              try:
                  user.set_password(new_second_password)
                  user.is_active = True
                  user.save()
                  return Response(
                      {"message": "비밀번호가 재설정 되었습니다!"}, status=status.HTTP_200_OK
                  )
              except Exception:
                  raise ParseError
 else:
       return Response({"error": "잘못된 접근입니다!"}, status=status.HTTP_403_FORBIDDEN)
              

token이 정상적으로 들어왔으면 그 토큰이 백엔드에서 해당 유저에게 보낸 토큰이 맞는지 확인한다. 맞으면 try로 요청을 정상적으로 처리하고, 틀리면 에러를 띄워서 비밀번호 도용을 막는다. 해결 완료!

아래는 클래스 전문.

class ResetPasswordView(APIView):
  def put(self, request):
          uidb64 = request.data.get("uidb64")
          token = request.data.get("token")
          user_id = request.data.get("user_id")
          new_first_password = request.data.get("new_first_password")
          new_second_password = request.data.get("new_second_password")
          try:
              user = User.objects.get(id=user_id)
          except User.DoesNotExist:
              return Response(
                  {"error": "일치하는 유저가 존재하지 않습니다!"},
                  status=status.HTTP_400_BAD_REQUEST,
              )
          if not uidb64 or not token:
              return Response({"error": "잘못된 접근입니다!"}, status=status.HTTP_403_FORBIDDEN)
          if not new_first_password or not new_second_password:
              return Response(
                  {"error": "비밀번호 입력은 필수입니다!"}, status=status.HTTP_400_BAD_REQUEST
              )
          if new_first_password != new_second_password:
              return Response(
                  {"error": "비밀번호가 일치하지 않습니다!"},
                  status=status.HTTP_400_BAD_REQUEST,
              )
          if len(new_second_password) < 8:
              return Response(
                  {"error": "비밀번호는 8자리 이상이어야 합니다."}, status=status.HTTP_400_BAD_REQUEST
              )
          if not re.search(r"[a-zA-Z]", new_second_password):
              return Response(
                  {"error": "비밀번호는 하나 이상의 영문이 포함되어야 합니다."},
                  status=status.HTTP_400_BAD_REQUEST,
              )
          if not re.search(r"\d", new_second_password):
              return Response(
                  {"error": "비밀번호는 하나 이상의 숫자가 포함되어야 합니다."},
                  status=status.HTTP_400_BAD_REQUEST,
              )
          if not re.search(r"[!@#$%^&*()]", new_second_password):
              return Response(
                  {"error": "비밀번호는 적어도 하나 이상의 특수문자(!@#$%^&*())가 포함되어야 합니다."},
                  status=status.HTTP_400_BAD_REQUEST,
              )
          if account_activation_token.check_token(user, token):
              try:
                  user.set_password(new_second_password)
                  user.is_active = True
                  user.save()
                  return Response(
                      {"message": "비밀번호가 재설정 되었습니다!"}, status=status.HTTP_200_OK
                  )
              except Exception:
                  raise ParseError
          else:
              return Response({"error": "잘못된 접근입니다!"}, status=status.HTTP_403_FORBIDDEN)
            

에러핸들링 완료!

Cookai 바로가기
설문조사 바로가기

profile
스프링 개발자 지망생입니다

0개의 댓글