DRF 中的身份验证与权限

身份验证与权限

前面举例项目的API对谁可以编辑或删除项目没有任何限制。而希望有一些更高级的行为,以确保:

  • 项目总是与创建者相关联。
  • 只有经过身份验证(登录后)的用户才能创建项目。
  • 只有项目的创建者才能更新或删除它。
  • 未经身份验证(游客)的请求应该具有完全只读访问权限。

modules.py 如下:
方便演示这里直接使用auth应用的User模型

from django.db import models

class Student(models.Model):
    """
    学生表
    """
    name = models.ForeignKey('auth.User', verbose_name='学生姓名',null=True, help_text='学生姓名', on_delete=models.SET_NULL,
                             related_name='student')
    gender = models.SmallIntegerField('性别', default='1', help_text='性别')
    hobby = models.CharField('爱好', max_length=200, null=True, blank=True, help_text='兴趣爱好')
    age = models.IntegerField('年龄', null=True, )
    create_time = models.DateTimeField('创建时间', auto_now_add=True, help_text='创建时间')

    class Meta:
        """
        元数据,
        """
        db_table = 'student'  # 指定当前模型创建的表明,不写默认当前的模型名Student
        verbose_name = '学生信息表'  # 注释
        verbose_name_plural = verbose_name  # 指定为复数

    def __str__(self):
        return f'name:{self.name},hobby:{self.hobby}'  # 输出项目名称,方便于调式


class Subject(models.Model):
    name = models.CharField(verbose_name='科目名称', max_length=100, null=True)
    sutdent = models.ForeignKey(Student, on_delete=models.CASCADE)  # 级联删除,删除主表数据时从表数据也会删除
创建用户

创建不同的用户用于测试API

python manage.py createsuperuser

最好将这些用户的表示添加到的API中,因此需要创建用户的序列化器。serializers.py代码如下:

from rest_framework import serializers
from project2s.models import Student, Subject
from django.contrib.auth.models import User

class ProjectSerializers(serializers.ModelSerializer):

    name = serializers.ReadOnlyField(source='name.username')
    class Meta:
        model = Student
        fields = ['id', 'name', 'hobby', 'age']

class SubjectSerializers(serializers.ModelSerializer):
    class Meta:
        model = Subject
        fields = '__all__'


class UserSerializers(serializers.ModelSerializer):
    student = serializers.PrimaryKeyRelatedField(many=True, queryset=Student.objects.all()) #因为'student'是用户模型的反向关系, 默认情况下,在使用ModelSerializer类时将不包含它,所以需要为它添加一个显式字段。

    class Meta:
        model = User
        fields = ['id', 'username', 'student']

在views.py中添加几个视图。希望只对用户表示使用只读视图,因此使用通用视图ListAPIView和RetrieveAPIView。

from project2s.models import Student, Subject
from django.contrib.auth.models import User
from project2s.serializers import ProjectSerializers, SubjectSerializers, UserSerializers
from rest_framework importgenerics
from rest_framework import permissions

# 类视图

class ListCreateView(generics.ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = ProjectSerializers
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]  # 添加权限

    def perform_create(self, serializer):
        serializer.save(name=self.request.user)

class UpdatePutDeleteDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = ProjectSerializers
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]  


class ListSubjectView(generics.ListCreateAPIView):
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializers


class ListUserView(generics.ListCreateAPIView): # 用户只读
    queryset = User.objects.all()
    serializer_class = UserSerializers


class UserDetailView(generics.RetrieveAPIView): # 用户详情
    queryset = User.objects.all()
    serializer_class = UserSerializers

urls.py路由配置

from django.urls import path
from project2s import views
from rest_framework.urlpatterns import format_suffix_patterns

app_name = 'project2s'

urlpatterns = [
    path('students/', views.ListCreateView.as_view()),  # 创建或展示
    path('students/<int:pk>/', views.UpdatePutDeleteDetailView.as_view()),  # 删除或显示
    path('subject/', views.ListSubjectView.as_view()),  # 查看
    path('user/', views.ListUserView.as_view()),  # 查看
    path('user/<int:pk>', views.UserDetailView.as_view())  # 查看详情
]

urlpatterns = format_suffix_patterns(urlpatterns)

关联项目与用户

现在可以创建项目,并手动选择对应的用户与项目进行关联。但是在某些场景下这可能不是你想要的,比如谁创建项目就把谁与创建的项目进行关联。

那么用户就不能再作为序列化表示的一部分发送,而是传入请求的一个属性。django会将当前用户对象设置到request.user属性上,它是在中间件AuthenticationMiddleware中完成的。

首先修改项目的序列化器,将name字段修改为只读,并显示用户的用户名。

class ProjectSerializers(serializers.ModelSerializer):
    name = serializers.ReadOnlyField(source='name.username')

    class Meta:
        model = Student
        fields = ['id', 'name', 'hobby', 'age']

source参数控制哪个属性用于填充字段,并可以指向序列化实例上的任何属性。它也可以采用上面所示的句点符, 在这种情况下,它将遍历给定的属性, 与Django的模板语言使用的方式类似。

ReadOnlyField始终是只读的,并将用于序列化表示,但当模型实例被反序列化时,将不会用于更新它们。

然后再重写项目视图上的perform_create()方法,修改保存实例保存的方式,处理隐式传入请求或者请求URL中的任何信息,这里我们给项目关联当前用户。

在ListCreateView视图类上,添加以下方法:

class ListCreateView(generics.ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = ProjectSerializers

    def perform_create(self, serializer):
        serializer.save(name=self.request.user)

添加登录功能

此时创建项目你会发现报错,这是因为,django再未做身份验证的请求的user属性上绑定了一个AnonymousUser对象。我们需要能够以用户身份登录。

通过编辑根urls.py文件中的URLconf,我们可以添加一个login视图来与可浏览的API一起使用。

在文件的末尾,添加一个模式,以包含可浏览API的登录和注销视图。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('project2s.urls')),
    path('auth', include('rest_framework.urls'))  # 登录功能

]

模式的’auth/'部分实际上可以是你想使用的任何URL。

现在,如果你再次打开浏览器并刷新页面,你会在页面的右上角看到一个“Login”链接。登录之前创建的用户,你将能够再次创建项目。

视图添加权限

现在希望确保只有经过身份验证的用户才能创建、更新和删除项目。REST框架包括许多权限类,我们可以使用它们来限制谁可以访问给定的视图。在这个例子中,我们要找的是IsAuthenticatedOrReadOnly,这将确保经过身份验证的请求获得读写访问权限,而未经身份验证的请求获得只读访问权限。

首先在views模块中添加以下导入

from rest_framework import permissions

然后,将下列属性添加到ListCreateView和UpdatePutDeleteDetailView视图类中。

class ListCreateView(generics.ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = ProjectSerializers
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]  # 添加权限

    def perform_create(self, serializer):
        serializer.save(name=self.request.user)

class UpdatePutDeleteDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = ProjectSerializers
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]  # 未登录时校验权限

permission_classes = [permissions.IsAuthenticatedOrReadOnly]
现在退出登录,会发现在项目列表页面的POST请求表单不见了
在这里插入图片描述
学生详情页的update,put按钮也看不见了
在这里插入图片描述

对象级权限

在这里插入图片描述

再创建一个用户并登录,会发现可以对前面用户创建的项目进行编辑。
实际上,希望所有项目对任何人都可见,但也要确保只有创建了项目的用户才能更新或删除它。

为此,需要创建一个自定义的权限。
在projects应用程序中,创建一个新文件permissions.py,编写如下代码:

from rest_framework import permissions
class IsStudentOrReadonly(permissions.BasePermission):
    """
    自定义权限只允许对象的学生编辑
    """
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.name == request.user

将它添加到UpdatePutDeleteDetailView视图上

class UpdatePutDeleteDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = ProjectSerializers
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,IsStudentOrReadonly]  # 未登录时校验权限
permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly]

刷新后只有当登录用户与当前代码片段的创建用户相同时,DELETE和PUT按钮才会出现在页面上。
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久醉绕心弦,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值