权限校验

   权限校验和认证校验必须同时使用,并且权限校验是排在认证校验之后的,这在源码中可以查找到其执行顺序。

   权限校验也很重要,认证校验可以确保一个用户登录之后才能对接口做操作,而权限校验可以依据这个登录用户的类型来限定能对接口做那些操作。

准备工作

模型表

   下面是模型表,对于不同等级的用户,访问同一url,能够获取到的电影内容也不一样。

  1. from django.db import models
  2. # Create your models here.
  3. class User(models.Model):
  4. user_id = models.AutoField(primary_key=True)
  5. user_name = models.CharField(max_length=32)
  6. user_password = models.CharField(max_length=32)
  7. user_type = models.IntegerField(choices=(
  8. [0,"普通用户"],
  9. [1,"黄金VIP"],
  10. [2,"钻石VIP"],
  11. ))
  12. user_token = models.CharField(max_length=64, null=True, unique=True)
  13. class Film(models.Model):
  14. film_id = models.AutoField(primary_key=True)
  15. film_name = models.CharField(max_length=32)
  16. film_grade = models.IntegerField(
  17. choices=(
  18. [0,"免费电影"],
  19. [1,"黄金VIP专享"],
  20. [2,"钻石VIP专享"]
  21. )
  22. )

   用户表数据如下:

  

   电影表数据如下:

  

序列类

   采用模型类序列器,并且只对电影做序列化:

  1. from rest_framework import serializers
  2. from app01 import models
  3. class FilmModelSerializers(serializers.ModelSerializer):
  4. class Meta:
  5. model = models.Film
  6. fields = "__all__"

认证校验

   下面是认证权限,只有登录后的用户才可以看到电影信息。如果没有登录将不允许查看所有电影的页面,或者你也可以不设置认证校验,但是在权限设置中可以设置匿名用户直接返回一个False也行。

  1. from rest_framework.authentication import BaseAuthentication
  2. from rest_framework.exceptions import APIException
  3. from app01 import models
  4. class LoginAuth(BaseAuthentication):
  5. def authenticate(self,request):
  6. token = request.META.get("HTTP_TOKEN")
  7. if not token:
  8. # 未登录
  9. raise APIException("未登录,无法查看本电影网站,请先登录")
  10. user_obj = models.User.objects.filter(user_token=token).first()
  11. if not user_obj:
  12. raise APIException("token无效,登录失败")
  13. else:
  14. return user_obj,user_obj.user_type # 将用户对象本身以及用户的类型存储到request.user以及request.auth中

视图

   下面是视图的代码:

  1. from uuid import uuid4
  2. from rest_framework.generics import ListAPIView
  3. from rest_framework.generics import GenericAPIView
  4. from rest_framework.views import APIView
  5. from rest_framework.views import Response
  6. from app01 import models
  7. from app01 import serializationClass
  8. from app01 import app01_auth
  9. class FilmAPI(ListAPIView,GenericAPIView):
  10. authentication_classes = [app01_auth.LoginAuth] # 必须登录
  11. queryset = models.Film.objects.all() # 默认查看所有,任何用户都是
  12. serializer_class = serializationClass.FilmModelSerializers
  13. def get(self,request):
  14. return self.list(request)
  15. class Login(APIView):
  16. def post(self,request):
  17. user_dict = {
  18. "user_name":request.data.get("user_name"),
  19. "user_password":request.data.get("user_password"),
  20. }
  21. user_obj = models.User.objects.filter(**user_dict).first()
  22. if not user_obj:
  23. return Response(data="用户名或密码错误")
  24. else:
  25. token = uuid4() # 创建token
  26. user_obj.user_token = token
  27. user_obj.save()
  28. return Response(data="登录成功",headers={"token":token}) # 返回token到请求头中

url

   下面是路由。

  1. from django.contrib import admin
  2. from django.urls import path
  3. from app01 import views
  4. urlpatterns = [
  5. path('admin/', admin.site.urls),
  6. path('login/',views.Login.as_view()),
  7. path('api/film/',views.FilmAPI.as_view()),
  8. ]

简单尝试

   现在我们启动django项目试试。可以发现,当我们在请求头中设置好token并朝api发送GET请求时,它会返回所有的数据。

   我们登录的是jack这个用户,他应该只能看到免费电影,而类似泰坦尼克号这种电影是不应该让他看见的。

  

自定制权限

   写一个类,继承BasePermission,重写has_permission()方法,如果权限通过,就返回True,不通过就返回False

权限校验

   接下来我们来写权限校验,has_permission()方法接受两个参数,分别是requestview,也就是视图类的实例化本身。

  1. from rest_framework.permissions import BasePermission
  2. from app01 import models
  3. from django.db.models import Q
  4. class UserPermission(BasePermission):
  5. def has_permission(self, request, view):
  6. if request.auth == 1: # 如果是普通用户,修改当前获取的资源为免费电影
  7. view.queryset = models.Film.objects.filter(film_grade=1)
  8. elif request.auth == 2: # 如果是黄金VIP,则只能获取黄金VIP电影和免费电影
  9. view.queryset = models.Film.objects.filter(Q(film_grade=2) | Q(film_grade=1))
  10. else:
  11. pass # 默认就是获取所有,所以不用修改
  12. return True # 权限校验完成,设置好了。普通用户只能看免费电影

局部使用

   下面是局部使用,只需要用一个变量名为permission_classes的列表,将权限校验的类放入即可:

  1. class FilmAPI(ListAPIView,GenericAPIView):
  2. authentication_classes = [app01_auth.LoginAuth] # 必须登录
  3. permission_classes = [app01_permissions.UserPermission] # 做权限设置
  4. queryset = models.Film.objects.all() # 默认查看所有,任何用户都是
  5. serializer_class = serializationClass.FilmModelSerializers
  6. def get(self,request):
  7. return self.list(request)

全局使用

   如果是全局使用,则需要到项目全局文件夹下的settings.py中进行设置:

  1. # 全局使用
  2. REST_FRAMEWORK={
  3. 'DEFAULT_PERMISSION_CLASSES': [
  4. 'app01.app01_permissions.UserPermission',
  5. ],
  6. }

   如果想取消某个接口的权限认证设置,则在其中设置类属性permission_classes是一个空列表。

   如下所示,登录功能不需要验证权限,我们对他取消掉即可。

  1. class Login(APIView):
  2. permission_classes = [] # 取消权限验证设置
  3. def post(self,request):
  4. user_dict = {
  5. "user_name":request.data.get("user_name"),
  6. "user_password":request.data.get("user_password"),
  7. }
  8. user_obj = models.User.objects.filter(**user_dict).first()
  9. if not user_obj:
  10. return Response(data="用户名或密码错误")
  11. else:
  12. token = uuid4() # 创建token
  13. user_obj.user_token = token
  14. user_obj.save()
  15. return Response(data="登录成功",headers={"token":token}) # 返回token到请求头中

结果演示

   再次使用jacktoken进行登录,可以发现他只会看到免费电影了。

  

   而使用kentoken进行登录,他将看不到钻石VIP的电影,如泰坦尼克号:

  

   倘若使用yunyatoken进行登录,则可以查看到所有的电影。

  

内置权限

   如果你是使用auth组件来做的一系列登录等,则可以使用内置权限。

   它会判断该用户的is_staff字段是否为True

   内置权限的类使用有很多,如下所示:

  

基本演示

  1. # 演示一下内置权限的使用:IsAdminUser,控制是否对网站后台有权限的人
  2. # 1 创建超级管理员
  3. # 2 写一个测试视图类
  4. from rest_framework.permissions import IsAdminUser
  5. from rest_framework.authentication import SessionAuthentication
  6. class TestView3(APIView):
  7. authentication_classes=[SessionAuthentication,] # 必须有认证
  8. permission_classes = [IsAdminUser] # 权限设置
  9. def get(self,request,*args,**kwargs):
  10. return Response('这是22222222测试数据,超级管理员可以看')
  11. # 3 超级用户登录到admin,再访问test3就有权限
  12. # 4 正常的话,普通管理员,没有权限看(判断的是is_staff字段)

源码分析

   权限校验排在认证校验之后,这在源码中可以查看到。

   它的源码相比于认证的源码来说简单的多,认证的执行是在request.user中进行的,而它直接是在当前视图类中进行,所以很简单。

  1. # APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的对象方法)
  2. def check_permissions(self, request):
  3. # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证 遍历 for (权限认证的实例化对象)
  4. for permission in self.get_permissions():
  5. # 权限类一定有一个has_permission权限方法,用来做权限认证的
  6. # 参数:权限对象self、请求对象request、视图类对象
  7. # 返回值:有权限返回True,无权限返回False
  8. if not permission.has_permission(request, self):
  9. self.permission_denied(
  10. request, message=getattr(permission, 'message', None)
  11. )

drf 权限校验设置与源码分析的更多相关文章

  1. django身份认证、权限认证、频率校验使用及源码分析

    一. 身份认证源码分析 1.1 APIView源码的分析 APIView源码之前分析过https://www.cnblogs.com/maoruqiang/p/11135335.html,里面主要将r ...

  2. drf复习(一)--原生djangoCBV请求生命周期源码分析、drf自定义配置文件、drf请求生命周期dispatch源码分析

    admin后台注册model  一.原生djangoCBV请求生命周期源码分析 原生view的源码路径(django/views/generic/base.py) 1.从urls.py中as_view ...

  3. ABP源码分析二十二:Navigation

    MenuDefinition:封装了导航栏上的主菜单的属性. MenuItemDefinition:封装了主菜单的子菜单的属性.子菜单可以引用其他子菜单构成一个菜单树 UserMenu/UserMen ...

  4. Log4j2异步情况下怎么防止丢日志的源码分析以及队列等待和拒绝策略分析

    org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor以下所有源码均在此类中首先我们看下log4j2异步队列的初始化 从这里面我们 ...

  5. drf 认证校验及源码分析

    认证校验 认证校验是十分重要的,如用户如果不登陆就不能访问某些接口. 再比如用户不登陆就不能够对一个接口做哪些操作. drf中认证的写法流程如下: 1.写一个类,继承BaseAuthenticatio ...

  6. Django(63)drf权限源码分析与自定义权限

    前言 上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析 源码入口:APIView.py文件下的initial方法下的check_per ...

  7. Django之DRF源码分析(二)---数据校验部分

    Django之DRF源码分析(二)---数据校验部分 is_valid() 源码 def is_valid(self, raise_exception=False): assert not hasat ...

  8. drf源码分析系列---权限

    权限的使用 全局使用 from rest_framework.permissions import BasePermission from rest_framework import exceptio ...

  9. DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用

    CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()),  --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...

随机推荐

  1. zookeeper watch笔记

    ZK其核心原理满足CP, 实现的是最终一致性, 它只保证顺序一致性. zookeeper 基于 zxid 以及阻塞队列的方式来实现请求的顺序一致性.如果一个client连接到一个最新的 followe ...

  2. JS进阶系列-JS执行期上下文(一)

    ❝ 点赞再看,年薪百万 本文已收录至https://github.com/likekk/-Blog欢迎大家star,共同进步.如果文章有出现错误的地方,欢迎大家指出.后期将在将GitHub上规划前端学 ...

  3. 【保姆级教程】手把手教你进行Go语言环境安装及相关VSCode配置

    [Go语言入门系列]前面的文章: [Go语言入门系列](七)如何使用Go的方法? [Go语言入门系列](八)Go语言是不是面向对象语言? [Go语言入门系列](九)写这些就是为了搞懂怎么用接口 本篇文 ...

  4. 054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述

    054 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 01 数组概述 本文知识点:数组概述 为什么要学习数组? 实际问题: 比如我们要对学生的成绩进行排序,一个班级 ...

  5. 01 C语言基本介绍

    C语言特点 容易上手学习 结构化语言 执行效率高 处理的工作和活动偏底层 可以在多种计算机平台上编译(类似Java的跨平台) C语言历史 目前,C 语言是最广泛使用的系统程序设计语言之一 C 语言是最 ...

  6. TCHAR数据类型介绍

    转载:https://blog.csdn.net/mousebaby808/article/details/5259944 并不是所有的Windows操作系统都支持UNICODE编码的API(例如早期 ...

  7. ESP8266 玩板记

    一.前言 esp8266的玩板记,后面应该会去更一些其他东西,这一块内容,这算是收官之战了. IoT,江湖有缘再相会 二.ESP8266实现WiFi杀手/钓鱼 这次的博客做的是一个娱乐性较强的项目. ...

  8. mycat ER分片

    有一类业务,例如订单(ORDER)跟订单明细表(ORDER_DETAIL),明细表会依赖于订单,就是该会存在表的主从关系,这类似业务的切分可以抽象出合适的切分规则,比如根据用户ID切分,其它相关的表都 ...

  9. mysql任意文件读取漏洞复现

    前言 第一次得知该漏洞后找了一些文章去看. 一开始不明白这个漏洞是怎么来的,只知道通过在服务端运行poc脚本就可以读取客户端的任意文件,直接找到网上准备好的靶机进行测试,发现可行,然后就拿别人的poc ...

  10. JVM(五):JVM模型与GC

    确定垃圾 引用计数(存在循环引用问题) 根可达算法 常见的垃圾回收算法 标记清除算法-位置不连续,产生碎片 拷贝算法- 没有碎片,浪费空间 标记压缩-没有碎片,效率偏低(多线程需要进行线程同步,单线程 ...