Seite 1 von 1

Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 13:37
von frogi001
Hallo,
habe ein Problem mit den permissions im DRF:

habe eine Model:

Code: Alles auswählen

from django.db import models

class lic_test(models.Model):
    id = models.AutoField(primary_key='true')
    lfn = models.IntegerField(default=0,blank=True) 
    lic = models.CharField(max_length=128,blank=True)
die serializers.py:

Code: Alles auswählen

from rest_framework import serializers
from .models import lic_test   

class licSerializer(serializers.ModelSerializer):
    class Meta:
        model = lic_test       
        fields = '__all__'   
und die view dazu:

Code: Alles auswählen

from django.shortcuts import render
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
from .models import lic_test
from .serializers import licSerializer

class liclist(APIView):
    permission_classes = [IsAuthenticated]

    def get(self,request):
        if 'lfn' in request.data:
            nr = request.data['lfn']
            lic1 = lic_test.objects.filter(lfn__in=nr)
        else:
            lic1 = lic_test.objects.all()
        serializer = licSerializer(lic1, many= True)
        return Response(serializer.data)
       
    def post(self, request):
        lic_data = JSONParser().parse(request)
        lic_serializer = licSerializer(data=lic_data)
        if lic_serializer.is_valid():   
            lic_serializer.save()           
            return JsonResponse(lic_serializer.data, status=status.HTTP_201_CREATED) 
        return JsonResponse(lic_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Im Django-Admin-Bereich habe ich einen Superuser, und einen "normalen" User angelegt.


Mit

Code: Alles auswählen

data = {'lfn':[29]}
data = {'lfn':[]}
data = {} 
response = requests.get("http://*****", json=data, auth=HTTPBasicAuth('user', 'pass'))
response = requests.post("http://*****", json=data, auth=HTTPBasicAuth('user', 'pass'))
kann ich GET und/oder POST-Requests senden, und bekomme auch immer die korrekten JSON-Daten zurückgeliefert,
bzw. neue Datensätze werden angelegt.


Soweit alles ok.
Mit der Einstellung:

Code: Alles auswählen

permission_classes = [DjangoModelPermissions]
kann ich wohl die Django Standard Permissions benutzen.
Hierzu muss ich aber in der view die

Code: Alles auswählen

.queryset
property oder die

Code: Alles auswählen

get_queryset()
Methode implementieren.

Ab hier beißt es aber aus :?

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 14:11
von sparrow
Du solltest Klassen so benennen, wie sie laut Konvention benannt werden sollen. CamelCase.

Was genau ist deine Frage?

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 17:57
von frogi001
Hallo,
Du solltest Klassen so benennen, wie sie laut Konvention benannt werden sollen. CamelCase.
... stimmt, das ist wirklich schlampig!

Ich will dem "normalen" user XY im Admin-Bereich Rechte geben, oder auch entziehen.
Dort kann man ja für ein model ( in diesem Fall für das Model: lic_test )
die Rechte :
  • add lic_test
  • change lic_test
  • delete lic_test und
  • view lic_test
setzen, oder auch wieder entziehen.

---
... noch etwas zum Coding-Style: wie gesagt, stimmt ... ist nicht nur schlechter Stil, sonder
wahrscheinlich auch kontraproduktiv!
Da gibt es ein "PEP 8 -- Style Guide for Python Code" ... kann ich das als "Grundlage für
korrekten Python-Code-Style" nehmen, oder gibt es da auch andere Meinungen?

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 18:04
von sparrow
Genau, PIP 8 ist korrekt.
Der Vorteil ist, dass man bei LicTest sofort sehen würde, dass es sich um eine Klasse handelt.
Ich würde übrigens auch sprechende Namen verwenden. Ich habe keine Ahnung, was ein LicTest ist. Allerdings auch nicht was ein lfn und ein lic ist.

Genau für das beschriebene Szenario sind die DjangoModelPermissions da. Wie du ja schon korrekt aus der Dokumentation herausgelesen hast, funktioniert das nur, wenn der View ein Queryset hat, gegen das die Berechtigung geprüft werden kann. Im einfachsten Fall get_queryset implementieren und das Queryset zurückgeben, das alle Instanzen umfasst - wenn du es nicht einschränken willst. Also Model.objects.all()

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 18:34
von frogi001
Habe die view angepasst:

Code: Alles auswählen

from django.shortcuts import render
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
from .models import lic_test
from .serializers import licSerializer

class liclist(APIView):
    permission_classes = [IsAuthenticated]
    ########## NEU ##########
    def get_queryset(self):
        if request.user.has_permission('read_lic_test')
            return lic_test.objects.all()
        else:
            return None
    ####################
    def get(self,request):
        if 'lfn' in request.data:
            nr = request.data['lfn']
            lic1 = lic_test.objects.filter(lfn__in=nr)
        else:
            lic1 = lic_test.objects.all()
        serializer = licSerializer(lic1, many= True)
        return Response(serializer.data)
       
    def post(self, request):
        lic_data = JSONParser().parse(request)
        lic_serializer = licSerializer(data=lic_data)
        if lic_serializer.is_valid():   
            lic_serializer.save()           
            return JsonResponse(lic_serializer.data, status=status.HTTP_201_CREATED) 
        return JsonResponse(lic_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
habe die get_queryset-Methode aufgenommen :?:
Ungefähr so ?

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 18:40
von sparrow
Nein, du nimmst DjangoModelPermissions als PermissionClasses und nimmst in get_queryset keine Filterung vor, sondern gibst das ungefilterte Queyset zurück.

Code: Alles auswählen

    def get_queryset(self):
        return LicTest.objects.all()

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 18:59
von frogi001
Hallo,

ich habe die view nochmal angepasst:

Code: Alles auswählen

class liclist(APIView):
    permission_classes = [DjangoModelPermissions]
    ########## NEU ##########
    def get_queryset(self):
        return lic_test.objects.all()
Der User, der keine der 4 permissions hat, bekommt alle Datensätze zu sehen, was nicht sein sollte.

Aber noch seltsamer ist, wenn ich die get_queryset()-Methode nochmal anpasse, so wie nachfolgend:

Code: Alles auswählen

class liclist(APIView):
    permission_classes = [DjangoModelPermissions]
    ########## NEU ##########
    def get_queryset(self):
        return lic_test.objects.filter(id=1)
dann bekommt der User auch alle Datensätze zurückgeliefert :shock:

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 19:18
von sparrow
Hier erklärt jemand ausführlich, wie man es benutzt.

Re: Probleme mit permissons in DjangoRestFramework

Verfasst: Donnerstag 26. August 2021, 20:40
von frogi001
Hallo,
herzlichen Dank ... das klappt wunderbar!!

Zusammenfassung:

habe die view wie folgt angepasst:

Code: Alles auswählen

from django.shortcuts import render
from django.http.response import JsonResponse
from rest_framework.parsers import JSONParser
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
#from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions
from .models import lic_test
from .serializers import licSerializer
# Name der app ist 'erest'
from erest.permissions import OwnModPerm

class liclist(APIView):
    permission_classes = [OwnModPerm]
    #permission_classes = [DjangoModelPermissions]

    def get_queryset(self):
        return lic_test.objects.all()

    def get(self,request):
        if 'lfn' in request.data:
            nr = request.data['lfn']
            lic1 = lic_test.objects.filter(lfn__in=nr)
        else:
            lic1 = lic_test.objects.all()
        serializer = licSerializer(lic1, many= True)
        return Response(serializer.data)


    def post(self, request):
        lic_data = JSONParser().parse(request)
        lic_serializer = licSerializer(data=lic_data)
        if lic_serializer.is_valid():
            lic_serializer.save()
            return JsonResponse(lic_serializer.data, status=status.HTTP_201_CREATED)
        return JsonResponse(lic_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
neu ist eigentlich nur die get_queryset()-Methode und

Code: Alles auswählen

permission_classes = [OwnModPerm]
die wie folgt aussieht ( eine neue Datei permissions.py im App-Ordner ):

Code: Alles auswählen

from rest_framework import permissions
from rest_framework.permissions import (DjangoModelPermissions)

class OwnModPerm(DjangoModelPermissions):
    def __init__(self):
        self.perms_map['GET'] = ['%(app_label)s.view_%(model_name)s']
        #self.perms_map['POST'] = ['%(app_label)s.add_%(model_name)s']
Der ganze Aufwand ist NUR notwendig, wenn ich die Permissions für GET anpassen möchte.
Für PUT, POST und DELETE funktioniert alle auch mit:

Code: Alles auswählen

permission_classes = [DjangoModelPermissions]