一 前言
上篇博客分析了 restframework 框架的认证组件的执行了流程并自定义了认证类. 这篇博客分析 restframework 的权限组件执行流程. 入口函数依然是 APIView.initial.
权限的判断是在用户认证之后进行的, restframework 框架里面的自带的认证实现的功能很简单, 如下:
这个方法通常来讲会根据需求定制, 该方法执行结束后悔返回用户信息和其他数据, 根据需求, 在上篇博客我返回了用户对象和 token 值.
本来这些应该在上篇博客结束的, 主要是因为今天学习权限组件时又想到有些遗漏所以在这里补充.
二 权限组件执行流程
APIView.perform_authentication() 方法结束, 其实是根据 mro 列表找到的. 接下来执行 APIView.check_permissions() 方法, restframework 框架自带的权限类相当于没有, 因为所有需要进行权限认证的都是返回 True, 所以这个也需要根据实际需求来定制.
1. 执行 APIView.check_permissions
其实套路和认证组件很相似
2. 执行 APIView.get_permission
对比权限和认证的查找相关类的流程可以发现认证类是在实例化 Request 对象时就把认证类获取当作参数传进去了, 而权限类并没有. 猜测 restframework 框架只要需要进行用户认证, 所以虽然认证写的功能也不完善, 但是还是必要的, 而权限相关的认证和实际需求有关, 所以就没有这么麻烦, 猜测频率也一样, 也需要自己重写和配置.
3. 执行 APIView.permission_classes
经过这几步就可以找到权限类
三 自定义权限组件
其实基本步骤和认证组件一样
1. views.py
from app01 import permiss_classes
2. permiss_classes.py
- from rest_framework.permissions import BasePermission
- class LoginPermission(BasePermission):
- def has_permission(self, request, view):
- print(request.user, 'guanjian')
- user = request.user
- if user.user_type == 1:
- return True
- return False
3. 使用
只要用户权限满足才能获取相关信息, 所以在用户表中加了个字段用来标识用户权限的
- # models.py
- class UserInfo(models.Model):
- nid = models.AutoField(primary_key=True)
- name = models.CharField(max_length=32)
- password = models.CharField(max_length=32)
- age = models.IntegerField()
- gender = models.SmallIntegerField()
- book = models.ManyToManyField(to='Book', through='User2Book', through_fields=('user', 'book'))
- user_choice = ((0, '封禁用户'), (1, '普通用户'), (2, '超级用户'))
- user_type = models.IntegerField(default=0, choices=user_choice)
完整的 models.py
- from django.db import models
- # Create your models here.
- # book_obj.author.set(*[])
- # class UserToken(models.Model):
- # nid = models.AutoField(primary_key=True)
- # user = models.OneToOneField(to='UserInfo', default=1)
- # token = models.CharField(max_length=64, default='123456')
- class UserInfo(models.Model):
- nid = models.AutoField(primary_key=True)
- name = models.CharField(max_length=32)
- password = models.CharField(max_length=32)
- age = models.IntegerField()
- gender = models.SmallIntegerField()
- book = models.ManyToManyField(to='Book', through='User2Book', through_fields=('user', 'book'))
- user_choice = ((0, '封禁用户'), (1, '普通用户'), (2, '超级用户'))
- user_type = models.IntegerField(default=0, choices=user_choice)
- def __str__(self):
- return self.name
- class Meta:
- verbose_name = '用户表'
- verbose_name_plural = verbose_name
- # 用户拥有的图书表, 因为是多对多关系, 所以是中间表
- class User2Book(models.Model):
- nid = models.AutoField(primary_key=True)
- user = models.ForeignKey(to='UserInfo')
- book = models.ForeignKey(to='Book')
- class Book(models.Model):
- nid = models.AutoField(primary_key=True)
- name = models.CharField(max_length=32)
- price = models.IntegerField()
- publish = models.ForeignKey(to='Publish', to_field='nid')
- pub_date = models.DateTimeField(auto_now_add=True)
- author = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book', 'author'))
- def __str__(self):
- return self.name
- class Meta:
- verbose_name = '图书表'
- verbose_name_plural = verbose_name
- class Publish(models.Model):
- nid = models.AutoField(primary_key=True)
- name = models.CharField(max_length=32)
- email = models.EmailField()
- class Meta:
- verbose_name = '出版社表'
- verbose_name_plural = verbose_name
- def __str__(self):
- return self.name
- class Author(models.Model):
- nid = models.AutoField(primary_key=True)
- name = models.CharField(max_length=32)
- phone = models.CharField(max_length=32, default=15764503613)
- class Meta:
- verbose_name = '作者表'
- verbose_name_plural = verbose_name
- def __str__(self):
- return self.name
- class Book2Author(models.Model):
- nid = models.AutoField(primary_key=True)
- book = models.ForeignKey(to='Book', to_field='nid')
- author = models.ForeignKey(to='Author', to_field='nid')
- class Meta:
- verbose_name = '图书作者表'
- verbose_name_plural = verbose_name
四 配置自定义权限类
1. 局部配置
假设在用户认证通过后需要判断用户的权限, 那么需要在该视图类中定义一个参数 permission_classes
- class Book(APIView):
- authentication_classes = [authticate_classes.BookAuth]
- permission_classes = [permiss_classes.LoginPermission]
- # authentication_classes = []
- def dispatch(self, request, *args, **kwargs):
- return super().dispatch(request, *args, **kwargs)
- def get(self, request, id):
- print(request.user, '444')
- response = {'status': 100, 'msg': None}
- book_obj = models.Book.objects.filter(pk=id).first()
- if book_obj:
- book_ser = myser.BookSer(book_obj, many=False)
- response['book'] = book_ser.data
- else:
- response['msg'] = '图书没有对象'
- response['status'] = 101
- return Response(response)
2. 全局使用
全局使用的话需要在项目的 settings 中配置, 如下:
- REST_FRAMEWORK={
- 'DEFAULT_PERMISSION_CLASSES': ['app01.permiss_classes.LoginPermission']
- }
3. 局部禁用
局部禁用需要在视图类中定义一个空的 permission_classes
permission_classes = []
来源: https://www.cnblogs.com/zuanzuan/p/10435699.html