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

posted @ 2020-04-29 11:15  帅丶高高  阅读(596)  评论(0)    收藏  举报