这是我参与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:登录用户可以访问,或者当请求是只读的时候也可以访问,也就是请求方式为GET、HEAD或者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_staff 为 0,发送请求,发现失败了。
在
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,也会报错。