6-2 认证和权限-DRF权限
目录:
- DRF权限介绍
- APIView权限管理源码剖析
- DRF权限(不认证和其他用户认证)
一、DRF权限介绍
我们创建两个用户 gaogege 和 shabihong ,但是我们发现 通过 用户 shabihong 去更新 我们 gaogege 创建的数据,发现也是可以更新的,但是我们这个并不是我们想要的。还有,就是不认证的情况也可以去改我们的数据。
1.1、不认证能修改我们的数据

1.2、其他用户认证修改
说明:当然用户名和密码输入不成功的话,修改数据肯定是不成功的。

其实我们想要的很简单:先去判断 数据的创建者 跟我是一个人的时候,才能修改成功或者创建成功。如果不是一个人的话,那对不起,修改和创建数据都不成功。
二、APIView权限管理源码剖析
我们现在还是看看 ApiView的源码,选过django的人都知道,ApiView 继承了 View ,然后重写 了 dispatch 方法。废话不多说了,我们先来追踪 到到底在哪里。追踪还是一样 Ctrl 按键 + 类名或者方法名等。
generics.ListCreateAPIView -> GenericAPIView -> views.APIView => 找到 dispatch方法。
我们找到APIView中的 dispatch 方法:
class APIView(View):
def dispatch(self, request, *args, **kwargs):
....
try:
self.initial(request, *args, **kwargs)
.....
好啦,我们看到有一个 self. initial 方法。我们继续点击去看看 : Ctrl 按键 + self.initial:
class APIView(view):
....
def initial(self, request, *args, **kwargs):
.....
# Ensure that the incoming request is permitted
self.perform_authentication(request) #检查认证
self.check_permissions(request) #检查权限
self.check_throttles(request)
噢...原来它是先做了认证,再去做权限。好啦,我们继续看,看看它的默认权限是啥?继续来,走你。Ctrl 按键 + check_permissions,然后按照下面步骤走下去:
self.check_permissions -> get_permissions() -> self.permission_classes -> api_settings -> DEFAULTS
好啦,我们来看看它给的默认权限是啥:
DEFAULTS = {
....
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny', #在这里,这边啥权限没做,任何人都可以操作
),
...
}
所以啊,那我们咋办,我们是不是只需要改 APIView中的permission_classes拿过来,重写赋值一下,是不是就可以控制权限了。也就是这样:
class GameList(generics.ListCreateAPIView):
....
permission_classes = [] #重新定义 permission_classes ,我权限控制就会读取这个
三、DRF权限控制
其实我们就是为了解决 用户不认证 和 其他认证用户 去任意 修改数据的问题。好,那我们就根据源码提供给我们的思路,解决 用户不认证 和 其他任意认证用户 修改数据的问题。
3.1、解决用户不认证权限控制问题
说明:其实很简单就是重写一下permission_classes这个属性。我们来对 GameDetail 改造。
....
from rest_framework import permissions #导入权限模块
class GameList(generics.ListCreateAPIView):
.....
class GameDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Game.objects.all()
serializer_class = GameSerializer
#重写permission_classes属性
permission_classes = [permissions.IsAuthenticatedOrReadOnly] # IsAuthenticatedOrReadOnly 先判断你是否认证,不认证就只有只读权限
就这么简单。好啦,那我们看看他是怎么实现的。我们来看下 IsAuthenticatedOrReadOnly 实现的:Ctrl + IsAuthenticatedOrReadOnly 走你:
class IsAuthenticatedOrReadOnly(BasePermission):
"""
The request is authenticated as a user, or is a read-only request.
"""
def has_permission(self, request, view): #重写了BasePermission中的has_permission的方法
return bool(
request.method in SAFE_METHODS or #SAFE_METHODS安全方法 Ctrl+SAFE_METHODS点进去看 => SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
request.user and
request.user.is_authenticated #用户认证
)
哈哈,搞明白了。看下 postman运行结果:
1、用户不认证
说明:哈哈哈,不可以修改了吧

2、用户认证
说明:完美解决

不认证也能修改成功 => permissions.IsAuthenticatedOrReadOnly 可以完美解决。
3.2、解决其他认证用户权限控制问题
说明:既然用户不认证我就让它只读,不让它修改。那我们现在来看看 其他用户认证的情况下,去修改 非自己的数据,那咋办呐?我们上面也看了 IsAuthenticatedOrReadOnly 源码了,那我们就照着IsAuthenticatedOrReadOnly这种方式,我们自己自定义 权限。
-app04
-migrations
...
-admin.py
-models.py
-permissions.py #新建权限py文件,专门存放自定义权限类
....
...
我们看了 IsAuthenticatedOrReadOnly 看到 它是继承 BasePermission 类。好,我们就来看看 BasePermission的源码是咋写的: Ctrl + 类名,走你:
IsAuthenticatedOrReadOnly => BasePermission
BasePermission源码如下:
@six.add_metaclass(BasePermissionMetaclass)
class BasePermission(object):
"""
A base class from which all permission classes should inherit.
"""
def has_permission(self, request, view): #数据获取方法,get方法
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
def has_object_permission(self, request, view, obj): #数据更新和删除权限,我们要重写这个方法
"""
Return `True` if permission is granted, `False` otherwise.
"""
return True
好家伙,我们在更改数据的(PUT)时候,只需要重写 has_object_permission方法就可以了。照着这个思路走。
1、自定义权限
说明:编辑 permissions.py文件
from rest_framework import permissions #导入权限模块
class IsOwnOrReadOnly(permissions.BasePermission):
#重写has_object_permission方法
def has_object_permission(self, request, view, obj): #obj表示当前数据对象(models中 User对象)
if request.method in permissions.SAFE_METHODS: #SAFE_METHOD:安全方法
return True
#print("obj", obj) #测试 obj,是当前模型(models)对象。返回的默认值是 models中 str() 方法的返回值
#print("request", request)
return obj.user == request.user # 创建用户的数据(obj.user) 是否跟 当前用户(request.user) 一样
2、编辑视图
说明:导入我们自定义的权限,然后用于权限认证
....
from rest_framework import permissions
from .permissions import IsOwnOrReadOnly #导入自定义认证权限,解决是否是当前用户修改数据
class GameList(generics.ListCreateAPIView):
...
class GameDetail(generics.RetrieveUpdateDestroyAPIView):
....
#可以支持多个权限认证
permission_classes = [permissions.IsAuthenticatedOrReadOnly,IsOwnOrReadOnly] #添加IsOwnOrReadOnly 自定权限
postman测试:
1、其他认证用户修改数据:shabihong

2、当前认证用修改数据:zhangqg


浙公网安备 33010602011771号