본문 바로가기

매일 TIL

[내일배움캠프 12-2일] django 개인과제 마무리, 트러블 슈팅(해결)

트러블 슈팅

 

문제 발생

IsAuthenticated 권한 클래스를 사용하여 Products 앱의 모든 기능에 인증된 사용자만 접근할 수 있도록 구현.

하지만 과제의 조건란을 자세히 읽어보니 상품 목록 조회에는 로그인 상태가 불필요하다는 것을 확인함.

결론적으로 상품 목록 조회, 상품 디테일 페이지 조회 기능에는 로그인하지 않아도 접근할 수 있도록 구현해야 하는 것.

하지만 어떻게 기능별로 IsAuthenticated를 적용, 미적용 시키는지 알지 못함.

class ProductListView(APIView):
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser, FormParser]

    def post(self, request):
        title = request.data.get("title")
        content = request.data.get("content")
        image = request.FILES.get("image")
        product = Product.objects.create(title=title, content=content, user=request.user, image=image)
        serializer = ProductSerializer(product)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def get(self, request):
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

class ProductDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, pk):
        product = get_object_or_404(Product, pk=pk)
        serializer = ProductSerializer(product)
        return Response(serializer.data, status=status.HTTP_200_OK)
   
    def put(self, request, pk):
        product = get_object_or_404(Product, pk=pk)
        if product.user != request.user:
            return Response({"message": "해당 게시글을 수정할 권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
        serializer = ProductSerializer(product, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        product = get_object_or_404(Product, pk=pk)
        if product.user != request.user:
            return Response({"error": "해당 게시글을 삭제할 권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
        product.delete()
        return Response({"message": "게시글이 삭제되었습니다."}, status=status.HTTP_204_NO_CONTENT)

이런 식으로 구현하다보니 상품 목록, 상품 디테일 페이지 조회 시에도 토큰을 필요로 하는 상황 발생.

Postman에서도 토큰이 없으면 상품 목록 조회가 불가능.

 


문제 해결 중 위기 상황 발생

간단하게 필요한 메서드 내부에만 permission_classes = [IsAuthenticated]를 선언하면 된다고 생각했음.

class ProductListView(APIView):
    parser_classes = [MultiPartParser, FormParser]

    def post(self, request):
        permission_classes = [IsAuthenticated]
        title = request.data.get("title")
        content = request.data.get("content")
        image = request.FILES.get("image")
        product = Product.objects.create(title=title, content=content, user=request.user, image=image)
        serializer = ProductSerializer(product)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def get(self, request):
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

class ProductDetailView(APIView):

    def get(self, request, pk):
        product = get_object_or_404(Product, pk=pk)
        serializer = ProductSerializer(product)
        return Response(serializer.data, status=status.HTTP_200_OK)
   
    def put(self, request, pk):
        permission_classes = [IsAuthenticated]
        product = get_object_or_404(Product, pk=pk)
        if product.user != request.user:
            return Response({"message": "해당 게시글을 수정할 권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
        serializer = ProductSerializer(product, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        permission_classes = [IsAuthenticated]
        product = get_object_or_404(Product, pk=pk)
        if product.user != request.user:
            return Response({"error": "해당 게시글을 삭제할 권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
        product.delete()
        return Response({"message": "게시글이 삭제되었습니다."}, status=status.HTTP_204_NO_CONTENT)

이렇게 하면 되는 줄 알았다.

 

하지만 permission_classes를 개별 메서드 안에서 선언하는 구조는 올바르지 않다는 것을 알게 됨.

permission_classes = [IsAuthenticated]는 클래스 레벨에서 설정해야 한다는 것.

 


문제 해결

self.check_permissions(request)를 사용해서 문제를 해결함.

permission_classes를 클래스 레벨에서 선언하지 않고,  self.check_permissions(request)를 통해 IsAuthenticated 권한을 메서드에서 사용하게 되는 것.

즉 IsAuthenticated를 직접 permission_classes에 선언하지 않고, 권한 검사를 수동으로 수행하는 방법을 채택.

class ProductListView(APIView):
    parser_classes = [MultiPartParser, FormParser]

    def post(self, request):
        self.check_permissions(request)
        title = request.data.get("title")
        content = request.data.get("content")
        image = request.FILES.get("image")
        product = Product.objects.create(title=title, content=content, user=request.user, image=image)
        serializer = ProductSerializer(product)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def get(self, request):
        products = Product.objects.all()
        serializer = ProductSerializer(products, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class ProductDetailView(APIView):

    def get(self, request, pk):
        product = get_object_or_404(Product, pk=pk)
        serializer = ProductSerializer(product)
        return Response(serializer.data, status=status.HTTP_200_OK)
   
    def put(self, request, pk):
        self.check_permissions(request)
        product = get_object_or_404(Product, pk=pk)
        if product.user != request.user:
            return Response({"message": "해당 게시글을 수정할 권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
        serializer = ProductSerializer(product, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        self.check_permissions(request)
        product = get_object_or_404(Product, pk=pk)
        if product.user != request.user:
            return Response({"error": "해당 게시글을 삭제할 권한이 없습니다."}, status=status.HTTP_403_FORBIDDEN)
        product.delete()
        return Response({"message": "게시글이 삭제되었습니다."}, status=status.HTTP_204_NO_CONTENT)

필요한 기능에서만 self.check_permissions을 통해 인증된 사용자일 때 접근 가능하도록 구현.

토큰 없이도 상품 목록 조회가 잘 이루어지는 것을 확인.

게시글 상세 조회 역시 토큰 없이 잘 이루어진다.

 


개인 과제 완료

https://github.com/Kyuho09/spartamarket_DRF

 

GitHub - Kyuho09/spartamarket_DRF

Contribute to Kyuho09/spartamarket_DRF development by creating an account on GitHub.

github.com