10

ネストされた構造を持つ API を実装しています。

動物園だとしましょう。ケージ ID 1 を取得するためGET /api/cage/にケージのリストを取得するために呼び出すことができますが、そのケージ内の動物のリストを取得することもできます。GET /api/cage/1/GET /api/cage/1/animals/

私が抱えている問題は、許可に関するものです。ケージ自体が見える場合にのみ、ケージ内の動物を見ることができるはずです。関連する許可クラスにhas_object_permission()戻ると、ケージ自体を見ることができるはずです。True

何らかの理由で、has_object_permission()GET を実行すると呼び出されます/api/cage/1/has_permission()、 を呼び出すと呼び出されますGET /api/cage/1/animals/。またhas_permission()、権限を確認するためのオブジェクトへのアクセス権がありません。何か不足していますか?どうすればいいですか?

私のケージビューセットは多かれ少なかれこのように見えます

class CageViewSet(ModelViewSet):
    queryset = Cage.objects.all()
    serializer_class = CageSerializer
    permission_classes = [GeneralZooPermissions, ]
    authentication_classes = [ZooTicketCheck, ]

    def get_queryset(self):
        ... code to only list cages you have permission to see ...

    @detail_route(methods=['GET'])
    def animals(self, request, pk=None):
        return Request(AnimalSerializer(Animal.objects.filter(cage_id=pk), many=True).data)

GeneralZooPermissionsのクラスは次のようになります(現時点では)

class GeneralZooPermissions(BasePermission):
    def has_permission(self, request, view):
        return True

    def has_object_permission(self, request, view, obj):
        return request.user.has_perm('view_cage', obj)

これは DRF のバグのようです。詳細なルートは、正しい許可チェックを呼び出しません。この問題を DRF 開発者に報告しようとしましたが、報告が消えたようです。次に何をすべきかわからない。アイデア?

DRF で投稿した問題が戻ってきて、応答がありました。チェックのみのようで、意図した動作ではhas_permission()ありません。has_object_permission()これは私を助けません。この時点で、次のようなことを行う必要があります。

class CustomPermission(BasePermission):
    def has_permission(self, request, view):
        """we need to do all permission checking here, since has_object_permission() is not guaranteed to be called"""
        if 'pk' in view.kwargs and view.kwargs['pk']:
            obj = view.get_queryset()[0]
            # check object permissions here
        else:
            # check model permissions here

    def has_object_permission(self, request, view, obj):
        """ nothing to do here, we already checked everything """
        return True
4

2 に答える 2

24

OK、DRF のコードの束を読み、DRF GitHub ページに問題を投稿した後。

ビューが操作対象のオブジェクトを取得するためにhas_object_permission()呼び出した場合にのみ呼び出されるようです。get_object()

とにかくアクセス許可を確認するためにオブジェクトを取得する必要があり、それらが透過的に行われた場合、余分なデータベースクエリが追加されるため、これはある程度理にかなっています。

私のレポートに返信した人は、これを反映するためにドキュメントを更新する必要があると言いました. したがって、カスタムの詳細ルートを作成し、適切にアクセス許可をチェックする場合は、次のようにする必要があります。

class MyViewSet(ModelViewSet):
    queryset = MyModel.objects.all()
    ....
    permission_classes = (MyCustomPermissions, )
    
        @detail_route(methods=['GET', ])
        def custom(self, request, pk=None):
            my_obj = self.get_object() # do this and your permissions shall be checked
            return Response('whatever')
于 2016-05-23T17:29:45.200 に答える
0

を呼び出さない別のメソッドget_object()(POSTメソッドなど) を実行中にパーミッションを定義したい場合は、has_permission メソッドをオーバーライドできます。たぶん、この答えが役立つかもしれません( https://stackoverflow.com/a/52783914/12737833 )

あなたができるもう一つのことは、あなたのメソッドを呼び出すことができるように、check_object_permissionsあなたのメソッドの中で使うことです:POSThas_object_permission

@action(detail=True, methods=["POST"])
def cool_post(self, request, pk=None, *args, **kwargs):
    your_obj = self.get_object()
    self.check_object_permissions(request, your_obj)
于 2021-12-19T16:34:30.183 に答える