DRF 常用内置权限及自定义权限

2,373 阅读2分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

常用内置权限

不同的 API 拥有不同的访问权限。比如普通用户有读文章的权限,但是没有删除文章的权限。因此需要用到权限来进行 API 的管理。以下是 DRF 自带的常用权限:

  • permissions.AllowAny:允许所有人访问。
    这个权限写了跟没写一样,一般用不到。

  • permissions.IsAuthenticated:登录用户才能访问。
    判断条件是 request.user and request.user.is_authenticated

  • permissions.IsAdminUser:管理员才可以访问。
    判断条件是 request.user and request.user.is_staff

  • permissions.IsAuthenticatedOrReadOnly:登录用户可以访问,或者当请求是只读的时候也可以访问,也就是请求方式为 GETHEAD 或者 OPTIONS 中的一种。


使用示例

views.py

from rest_framework import viewsets
from meituan.models import Merchant
from .serializers import MerchantSerializer
from rest_framework.authentication import BasicAuthentication
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from .authentications import generate_jwt, JWTAuthentication


class MerchantViewSet(viewsets.ModelViewSet):
    queryset = Merchant.objects.all()
    serializer_class = MerchantSerializer

    # 指定认证方式,判断用户是否已经成功登录
    authentication_classes = [JWTAuthentication, BasicAuthentication]
    # 根据用户权限来限制访问
    permission_classes = [IsAuthenticated, IsAdminUser]


from django.contrib.auth import get_user_model
from rest_framework.response import Response
from rest_framework.decorators import api_view

User = get_user_model()


@api_view(['GET'])
def token_view(request):
    # 实际上需要通过认证才能返回 token
    # 这里仅仅用于演示
    token = generate_jwt(User.objects.first())
    return Response({'token': token})

指定了权限为 [IsAuthenticated, IsAdminUser],表明两者都要满足才能访问 API

Navicat 中修改 is_staff0,发送请求,发现失败了。

Navicat 中修改后记得使用快捷键 Ctrl-S 保存。

自定义权限

DRF 中,除了可以使用内置权限,还可以自定权限。

自定义权限有两个步骤:

  • 实现一个类,继承自 permissions.BasePermission
  • 实现 has_permission(self, request, view) 或者是 has_object_permission(self, request, view, obj) 方法。
    第一个方法用管理整个视图的访问权限,第二个方法可以用来管理某个对象的访问权限(比如只能修改自己的用户信息)。
    如果两个方法都定义了,必须首先通过 has_permission 的授权,才能进入到 has_object_permission 的授权。

permissions.py

from rest_framework.permissions import BasePermission


class MyPermission(BasePermission):
    def has_permission(self, request, view):
        # Referer
        if request.META.get('HTTP_REFERER'):
            return True
        return False

    def has_object_permission(self, request, view, obj):
        if '长沙' in obj.name:
            return True
        return False

views.py

from rest_framework import viewsets
from meituan.models import Merchant
from .serializers import MerchantSerializer
from rest_framework.authentication import BasicAuthentication
from .authentications import JWTAuthentication
from .permissions import MyPermission


class MerchantViewSet(viewsets.ModelViewSet):
    queryset = Merchant.objects.all()
    serializer_class = MerchantSerializer

    # 指定认证方式,判断用户是否已经成功登录
    authentication_classes = [JWTAuthentication, BasicAuthentication]
    # 权限控制
    permission_classes = [MyPermission]

使用 Postman 访问时,必须带上 Referer 请求头,否则会出现以下报错信息。

如果访问的商家详情的名字中不带 '长沙' 两个字,即便携带了 Referer,也会报错。