Django REST Framework - Terpisah permissions per metode

Saya menulis sebuah API menggunakan Django REST Framework dan saya bertanya-tanya jika dapat menentukan izin per metode ketika menggunakan kelas berdasarkan pandangan.

Membaca dokumentasi saya melihat bahwa cukup mudah untuk dilakukan jika anda menulis fungsi berdasarkan pandangan, hanya menggunakan @permission_classes dekorator alih fungsi dari pandangan anda ingin melindungi dengan izin. Namun, saya don't melihat cara untuk melakukan hal yang sama ketika menggunakan CBVs dengan APIView kelas, karena itulah aku menentukan hak akses untuk kelas penuh dengan permission_classes atribut, tapi yang akan diterapkan kemudian untuk semua metode kelas (get, post, masukan...).

Jadi, adalah mungkin untuk memiliki pandangan API tertulis dengan CBVs dan juga menentukan hak akses yang berbeda untuk masing-masing metode melihat kelas?

Mengomentari pertanyaan (1)

I've menemukan masalah yang sama ketika menggunakan CBV's, seperti yang telah saya cukup kompleks izin logika tergantung pada permintaan metode.

Solusi saya datang dengan adalah untuk menggunakan pihak ketiga 'rest_condition' aplikasi yang tercantum di bagian bawah halaman ini

http://www.django-rest-framework.org/api-guide/permissions

https://github.com/caxap/rest_condition

Aku hanya membagi izin aliran logika sehingga masing-masing cabang akan berjalan, tergantung pada permintaan metode.

from rest_condition import And, Or, Not

class MyClassBasedView(APIView):

    permission_classes = [Or(And(IsReadOnlyRequest, IsAllowedRetrieveThis, IsAllowedRetrieveThat),
                             And(IsPostRequest, IsAllowedToCreateThis, ...),
                             And(IsPutPatchRequest, ...),
                             And(IsDeleteRequest, ...)]

Jadi 'Atau' menentukan cabang izin yang harus dijalankan tergantung pada permintaan metode dan 'Dan' membungkus izin yang berkaitan dengan diterima metode permintaan, jadi semua harus melewati izin yang akan diberikan. Anda juga dapat mencampur 'Atau', 'Dan' dan 'Tidak' dalam masing-masing aliran untuk membuat bahkan lebih kompleks izin.

Izin kelas untuk menjalankan setiap cabang hanya terlihat seperti ini,

class IsReadyOnlyRequest(permissions.BasePermission):

    def has_permission(self, request, view):
        return request.method in permissions.SAFE_METHODS

class IsPostRequest(permissions.BasePermission):

    def has_permission(self, request, view):
        return request.method == "POST"

... #You get the idea
Komentar (0)
Larutan

Izin yang diterapkan untuk seluruh kelas, tapi anda bisa memperhitungkan aspek dari permintaan tersebut (seperti metode GET atau POST) dalam keputusan otorisasi.

Lihat built-in IsAuthenticatedOrReadOnly sebagai contoh:

SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']

class IsAuthenticatedOrReadOnly(BasePermission):
    """
    The request is authenticated as a user, or is a read-only request.
    """

    def has_permission(self, request, view):
        if (request.method in SAFE_METHODS or
            request.user and
            request.user.is_authenticated()):
            return True
        return False
Komentar (2)

Aku berlari ke dalam masalah ini dan benar-benar ingin menggunakan @permission_classes dekorator untuk menandai beberapa tampilan kustom metode dengan izin khusus. Saya akhirnya datang dengan mixin:

class PermissionsPerMethodMixin(object):
    def get_permissions(self):
        """
        Allows overriding default permissions with @permission_classes
        """
        view = getattr(self, self.action)
        if hasattr(view, 'permission_classes'):
            return [permission_class() for permission_class in view.permission_classes]
        return super().get_permissions()

Contoh kasus penggunaan:

from rest_framework.decorators import action, permission_classes  # other imports elided

class MyViewset(PermissionsPerMethodMixin, viewsets.ModelViewSet):
    permission_classes = (IsAuthenticatedOrReadOnly,)  # used for default ViewSet endpoints
    queryset = MyModel.objects.all()
    serializer_class = MySerializer

    @action(detail=False, methods=['get'])
    @permission_classes((IsAuthenticated,))  # overrides IsAuthenticatedOrReadOnly
    def search(self, request):
        return do_search(request)  # ...
Komentar (1)

Saya tahu ini adalah pertanyaan lama tapi aku baru saja berlari ke dalam masalah yang sama dan ingin berbagi solusi saya (sejak diterima jawaban itu't cukup apa yang saya butuhkan). @GDorn's jawaban menempatkan saya pada jalur yang benar, tetapi hanya bekerja dengan ViewSet karenadiri.aksi`

I've dipecahkan itu membuat saya sendiri dekorator:

python def method_permission_classes(kelas): def dekorator(func): def decorated_func(mandiri, *args, **kwargs): mandiri.permission_classes = kelas kembali func(mandiri, *args, **kwargs) kembali decorated_func kembali dekorator

Bukan menetapkan permission_classes properti pada fungsi, seperti built-in dekorator tidak, saya dekorator membungkus memanggil dan menetapkan izin kelas pada melihat contoh yang dipanggil. Dengan cara ini, normal get_permissions() doesn't membutuhkan perubahan, karena itu hanya bergantung pada diri.permission_classes.

Contoh kasus penggunaan:

``python dari rest_framework impor pandangan, izin

kelas MyView(pandangan.APIView): permission_classes = (permissions.IsAuthenticatedOrReadOnly,) # digunakan untuk default APIView endpoint queryset = MyModel.benda-benda.semua() serializer_class = MySerializer

@method_permission_classes((permissions.IsAdminUser,)) # menimpa IsAuthenticatedOrReadOnly def menghapus(mandiri, permintaan, id): contoh = self.get_object() # ... ``

Semoga ini bisa membantu seseorang menjalankan ke dalam masalah yang sama!

Komentar (0)