Django REST Framework笔记(七)认证与权限

到目前为止,DRF学习到了一定的程度,可以写很基础的接口了。

不过,离实际应用还差了很远。目前接口的情况:任何人都可以发起请求,实际应用时是不允许的。在传统的django开发中,有@login_required@permission_required 两个装饰器分别对身份和权限进行限制,不过在drf中内置有对应的方法。

所以现在要学习认证与权限。简单来说:

  • 认证 : 使用账号密码登陆,身份校验无误
  • 权限: 各种身份所匹配的操作,如匿名用户可创建用户、登陆的用户只能修改自己的信息、admin用户可以删除用户等等

同时,DRF的认证和权限集成到了一起。DRF的认证是基于django的默认User模块,前面的User都是我自己写的,并且和django自带的User没有半毛钱关系,所以,干脆重写了一个app:Author。 即,从这里开始,代码发生了改变。

  • authors/models.py
from django.db import models
from django.contrib.auth.models import User
from user.models import Company
from django.dispatch import receiver
from django.db.models.signals import post_save

"""
    One2One的模式:增加数据的时候,只能从默认User模型中选择对象
"""
class UserExtension(models.Model):
    user_name = models.OneToOneField(User, on_delete=models.CASCADE)
    cn_name = models.CharField(max_length=10)
    phone = models.CharField(('手机号码') ,max_length=11)
    company = models.ForeignKey(Company, on_delete=models.SET('公司已删除'))

#信号,使用系统自带的user增加数据时,自动为UserExtension新增一个实例
# @receiver(post_save, sender=User)
# def create_userextension(sender, instance, created, **kewargs):
#     if created:
#         UserExtension.objects.create(username=instance, company_id=1, phone='13800138000')
  • authors/serializers.py
from django.db.models import fields
from . models import UserExtension
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from django.contrib.auth.models import User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email')

class UserExListCreateSerializer(serializers.ModelSerializer):
    user_name = UserSerializer()
    
    class Meta:
        model = UserExtension
        fields = '__all__'
        depth = 1

class UserExDetailPutDeleteSerializer(serializers.ModelSerializer):
    user_name = serializers.CharField(read_only=True)

    class Meta:
        model = UserExtension
        fields = '__all__'
  • authors/views.py
from django.db.models.base import Model
from django.shortcuts import render
from .models import UserExtension
from . serializers import UserExListCreateSerializer, UserExDetailPutDeleteSerializer
from rest_framework.viewsets import ModelViewSet
from rest_framework import permissions

#自定义权限
class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        print(obj.user_name)
        print(request.user)
        if request.method in ('GET',):       # 判断请求方法未get时,任意用户都可以读
            return True
        return request.user == obj.user_name # 只有当前用户与obj的user_name相同时才能读写

class UserExViewSet(ModelViewSet):
    queryset = UserExtension.objects.all()
    # serializer_class = UserExSerializer
    permission_classes = (IsOwnerOrReadOnly, )

    def get_serializer_class(self):
        serializer_class = self.serializer_class
        if self.request.method in ('GET', 'POST'):
            serializer_class = UserExListCreateSerializer
            print(self.request)
            return serializer_class
        else:
            serializer_class = UserExDetailPutDeleteSerializer
            return serializer_class
  • authors/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('user/', views.UserExViewSet.as_view({'get': 'list', 'post': 'create'})),
    path('user/<int:pk>', views.UserExViewSet.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update'})),
]

DRF自带一些认证与权限的预设方案,如:

  • IsAuthenticatedOrReadOnly 认证用户可读写否则只读(这个有点不太适用,意味着A用户登陆了可以修改B用户的数据)
  • IsAuthenticated 认证用户 认证用户可读写否则拒绝访问
  • IsAdminUser 仅限管理员账号 这个还是蛮使用的,有些数据的确只允许管理员访问

更多权限可浏览源码rest_framework/permisions.py

重点解读自定义权限

这里需要理解一下自定义权限的逻辑。自定义权限要继承permissions.BasePermission 类,BasePermission里有两个方法需要理解的,分别是has_permissionhas_object_permission


class BasePermission(metaclass=BasePermissionMetaclass):
    """
    A base class from which all permission classes should inherit.
    """

    def has_permission(self, request, view):
        """
        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

经过测试,得出以下结论:
1、读写多个对象时,需要has_permission返回True,反之则无权限
2、读写单个对象时,需要has_object_permission 返回True,反之则无权限

上面我的自定义权限的写法为:

#自定义权限
class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        print(obj.user_name)
        print(request.user)
        if request.method in ('GET',):       # 判断请求方法未get时,任意用户都可以读
            return True
        return request.user == obj.user_name # 只有当前用户与obj的user_name相同时才能读写

分析一下:
1、当为get请求时,任意用户(包含匿名用户)均仅读
2、当request.user 和 当前所请求的obj中的user_name 一致时,可以读写。

这就实现了用户只能修改自己创建的数据,同时也可以读他人的数据。有两点需要说明一下:
1、request.user是django自带的User,即使用自带的user所创建的用户
2、obj.user_name 是appUserExtension的,这个字段和django自带的是One2One关系。

python代码是按顺序执行的,意味着,可以同时写几个权限的逻辑,但必须保证每一个逻辑都要有布尔返回值。

更多集成的权限设置方案

本案例中,权限是通过视图中的permision_class属性来设置的,这个权限仅在该视图中生效,如果某些权限要在全局生效,可以在settings中设置,DRF为我们提供了对应的全局设置方案。

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}

如果视图是基于函数的,还可以使用下面的装饰器:


from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated

@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
def func(request):	pass

能否在全局使用自定义权限策略呢?

暂时还不懂,跳过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值