• Django-restframework 之权限源码分析


    Django-restframework 之权限源码分析

    一 前言

    上篇博客分析了 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 = []
    
  • 相关阅读:
    二级目录下的SESSION共享问题
    [Leetcode 65] 120 Triangle
    JMeter学习(一)工具简单介绍
    pycham破解方法——Mac上亲测成功
    jmeter目前发现一丢丢强大的功能(未完待续,需优化)
    jmeter实现请求返回参数利用到下一个请求中
    通用化case,拿走不谢——测试之路
    mac 下pip安装python三方库的时候提示 Could not fetch URL https://pypi.python.org/simple/virtualenv/: There was a problem confirming the ssl certificate:......
    sudo pip install MySQLdb找不到该资源的原因
    软件质量管理实践总结
  • 原文地址:https://www.cnblogs.com/zuanzuan/p/10435699.html
Copyright © 2020-2023  润新知