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 = []
posted @ 2019-02-26 10:26  rsuxwvilc  阅读(433)  评论(0编辑  收藏  举报