Click to jump to the REST-Framework column directory
Authentication and permissions are used in combination to determine whether a request returns data or rejects requested data.
Determine the permissions
Before running the view should check each request permissions, if the check fails, will trigger exceptions. PermissionDenied abnormalities, and will not run view theme code.
When the check fails, return the 401 or 403 status code according to the following rules:
- The request was successfully authenticated but permission denied and will be returned
HTTP403
Forbidden response - The request was not authenticated successfully. The highest priority authentication class is not used
WWW-Authenticate
The header will returnHTTP403
Forbidden response - The request was not authenticated successfully, the highest priority authentication class did use
WWW-Authenticate
The header will return onehttp401
Unauthorized response with appropriateWWW-Authenticate
The header
Such as:
def get_object(self) :
obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.request, obj)
return obj
Copy the code
Note that, with the exception of DjangoObjectPermissions, the permission classes provided in rest_framework.Permission do not implement the methods required to check object permissions.
If you want to use the provided permission class to check object permissions, you must subclass it and implement the has_object_Permission () method described in the Custom permissions section.
For performance reasons, when a list of objects is returned, the generic view does not automatically apply object-level permissions to each instance in the query set.
In general, when you use object-level permissions, you also need to filter the query set appropriately to ensure that users can only see the instances they are allowed to see.
Setting permission Policies
In settings.py in a Django project, you can use global Settings to set permission access policies:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated']},Copy the code
Of course, if you do not specify this, the default is unlimited access:
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',]Copy the code
You can also set policies for individual ApiViews:
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView) :
permission_classes = [IsAuthenticated]
def get(self, request, format=None) :
content = {
'status': 'request was permitted'
}
return Response(content)
Copy the code
Or use a decorator to accessorize the policy:
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None) :
content = {
'status': 'request was permitted'
}
return Response(content)
Copy the code
Note: When you set a new permission class through the class property or decorator, you are telling the view to ignore the default list set on the settings.py file.
If they inherit from rest_framework. Permissions. BasePermission, you can use the standard Python bitwise operators to combine permissions, such as IsAuthenticatedOrReadOnly can write like this:
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.response import Response
from rest_framework.views import APIView
class ReadOnly(BasePermission) :
def has_permission(self, request, view) :
return request.method in SAFE_METHODS
class ExampleView(APIView) :
permission_classes = [IsAuthenticated|ReadOnly]
def get(self, request, format=None) :
content = {
'status': 'request was permitted'
}
return Response(content)
Copy the code
Note: it supports & (and), | (or) and ~ (not).
IsAuthenticated
Permission will be granted if the user has been authenticated and has passed authentication.
IsAdminUser
The license class is authenticated after the user instance user.is_staff is True in case the license will be allowed.
IsAuthenticatedOrReadOnly
Requests to unauthorized users are allowed only if the request method is one of the security methods: GET, HEAD, and OPTIONS.
DjangoModelPermissions
This permission class is associated with Django’s standard Django.contrib. auth model permissions, which can only be applied to views of the.queryset property and are granted only if the user is authenticated and assigned the associated model permissions.
POST
Requests require user pairsadd
Model has permissionsPUT
,PATCH
The request asks the user tochange
Model has permissionsDELETE
Requests require user pairsdelete
Model has permissions
Default behavior can also be overridden to support custom model permissions, such as view model permissions that you might want to include for GET requests.
To use custom model permissions, override DjangoModelPermissions and set the.perms_map attribute. Refer to the source code for more information.
If you use this permission with a view that overrides the get_querySet () method, there may be no QuerySet attribute on the view, in which case we recommend that you also use sentinel QuerySet to mark the view so that the class can determine the required permissions, for example:
queryset = User.objects.none() # Required for DjangoModelPermissions
Copy the code
DjangoModelPermissionsOrAnonReadOnly
Similar to DjangoModelPermissions, but also allows unauthenticated users to have read-only access to the API.
DjangoObjectPermissions
This permission class is associated with Djangos standard object permission framework, which allows object-specific permissions on models. To use this permission class, you also need to add a permission back end that supports object-level permissions, such as Django-Guardian.
As with DjangoModelPermissions, this permission must only apply to views that have the.querySet attribute or the.get_queryset() method, and authorization is granted only after the user has authenticated and assigned the associated permissions for each object and the associated model permissions.
POST
The request asks the user toadd
Model instances have permissionsPUT
,PATCH
The request asks the user tochange
Model instances have permissionsDELETE
The request asks the user todelete
Model instances have permissions
Note that DjangoObjectPermissions does not require the Django-Guardian package and should support other object-level backends as well.
As with DjangoModelPermissions, you can use custom model permissions by overriding DjangoObjectPermissions and setting the.perms_map attribute, refer to the source code for details.
Note: If you need object-level view permissions for GET, HEAD, and OPTIONS requests and are using Django-Guardian as an object-level permission back end, Need to consider to use djangorestframework – the guardian package provides DjangoObjectPermissionsFilter, it ensures that a list of the endpoint returns only results, including the user object with the proper view permissions.
Custom permissions
To implement custom permissions, override BasePermission and implement one or both of the following methods:
.has_permission(self, request, view)
.has_object_permission(self, request, view, obj)
Request access should be granted if the method should return True, otherwise return False.
If you need to test, if a request is a read or write operation, you should check SAFE_METHODS on constants, which is a tuple containing ‘GET’, ‘OPTIONS’, and ‘HEAD’, for example:
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
Copy the code
Note: The instance-level has_object_Permission method is called only if the view-level has_permission check has passed. Note also that in order to run instance-level checks, View code should explicitly call.check_object_permissions(request, Obj), if you are using a generic view, this will be handled for you by default (function-based views will need to explicitly check object permissions, raising PermissionDenied on failure).
If the test fails, the custom permission will raise the PermissionDenied exception. To change the error message associated with the exception, implement the message property directly on the custom permission. Otherwise, the default_detail property of PermissionDenied will be used. Also, to change the code identifier associated with the exception, implement the code attribute directly on your custom permission. Otherwise, the default_codeFrom property of PermissionDenied is used.
example
Here is an example of a permission class that checks the IP address of an incoming request against a block list and rejects the request if the IP is blocked:
from rest_framework import permissions
class BlocklistPermission(permissions.BasePermission) :
""" Global permission check for blocked IPs. """
def has_permission(self, request, view) :
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
Copy the code
In addition to global permissions that run on all incoming requests, you can create object-level permissions that run only on operations that affect specific object instances, such as:
class IsOwnerOrReadOnly(permissions.BasePermission) :
""" Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """
def has_object_permission(self, request, view, obj) :
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
Copy the code
Note that generic views will check the appropriate object-level permissions, but if you are writing your own custom views, you need to make sure you check the object-level permissions yourself, by calling self.check_object_permissions(request, Obj), if any object-level permission checks fail, the call will throw an APIException, otherwise it will simply return.
Also note that generic views will only check object level permissions for views that retrieve a single model instance, and if object level filtering for list views is required, query sets will need to be filtered separately. See the Filtering documentation for more details.