Django REST FrameWork中文教程4:验证和权限

目前,咱们的API对谁能够编辑或删除代码段没有任何限制。咱们想要一些更高级的行为,以确保:html

  • 代码段始终与建立者相关联。python

  • 只有身份验证的用户能够建立片断。sql

  • 只有片断的建立者能够更新或删除它。数据库

  • 未经身份验证的请求应具备彻底只读访问权限。django

将信息添加到咱们的模型

咱们将对咱们的Snippet模型类进行一些更改。首先,咱们添加几个字段。其中一个字段将用于表示建立代码段的用户。另外一个字段将用于存储代码的突出显示的HTML表示。编程

将如下两个字段添加到Snippet模型中models.pyapi

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()

  

咱们还须要确保在保存模型时,使用pygments代码突出显示库填充突出显示的字段。浏览器

咱们须要一些额外的导入:框架

from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight

  

如今咱们能够.save()在咱们的模型类中添加一个方法:ide

def save(self, *args, **kwargs):
    """
    Use the `pygments` library to create a highlighted HTML
    representation of the code snippet.
    """
    lexer = get_lexer_by_name(self.language)
    linenos = self.linenos and 'table' or False
    options = self.title and {'title': self.title} or {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                              full=True, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super(Snippet, self).save(*args, **kwargs)

  

完成这些工做后,咱们须要更新咱们的数据库表。一般咱们将建立一个数据库迁移,为了作到这一点,可是为了本教程的目的,咱们只需删除数据库并从新开始

rm -f tmp.db db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate

  

您可能还须要建立几个不一样的用户,以用于测试API。执行此操做的最快方法是使用createsuperuser命令。

python manage.py createsuperuser

  

为咱们的用户模型添加端点

如今咱们有一些用户可使用,咱们最好将这些用户的表示添加到咱们的API中。建立一个新的serializer很容易。在serializers.py添加:

from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

    class Meta:
        model = User
        fields = ('id', 'username', 'snippets')

  

由于在User模型上'snippets'是一个反向关系,因此在使用ModelSerializer该类时它不会被默认包含,因此咱们须要为它添加一个显式字段。

咱们还会添加几个视图views.py。咱们但愿只使用只读视图为用户表示,因此咱们将使用ListAPIViewRetrieveAPIView通用的基于类的意见。

from django.contrib.auth.models import User


class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

  

确保也导入UserSerializer

from snippets.serializers import UserSerializer

  

最后,咱们须要经过从URL conf引用它们将这些视图添加到API中。将如下内容添加到其中的模式中urls.py

url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),

  

将片断与用户关联

如今,若是咱们建立了一个代码片断,那么将没法将建立该代码段的用户与代码段实例相关联。用户不是做为序列化表示的一部分发送的,而是传入请求的属性。

咱们处理的方式是覆盖.perform_create()咱们的代码片断视图上的方法,这样咱们能够修改实例保存的管理方式,并处理传入请求或请求的URL中隐含的任何信息。

SnippetList视图类中,添加如下方法:

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

  

create()咱们的串行器的方法如今将被传递一个附加'owner'字段,以及请求中验证的数据。

更新咱们的serializer

如今,这些片断与建立它们的用户相关联,咱们更新咱们SnippetSerializer来反映这一点。将如下字段添加到序列化器定义中serializers.py

owner = serializers.ReadOnlyField(source='owner.username')

  

注意:确保您还添加'owner',到内部Meta类的字段列表。

这个领域正在作一些颇有趣的事情。的source哪一个属性参数控制用于填充的字段,而且能够在对串行化实例的任何属性点。它也能够采用上面显示的点划线,在这种状况下,它将以与Django模板语言一块儿使用的类似方式遍历给定的属性。

咱们添加了字段是类型化ReadOnlyField类,相对于其余类型的字段,如CharFieldBooleanField等...类型化ReadOnlyField始终是只读的,而且将用于序列化表示形式,但不会被用于更新模型他们被反序列化的实例。咱们也能够CharField(read_only=True)在这里使用。

添加视图所需的权限

如今,代码片断与用户相关联,咱们但愿确保只有通过身份验证的用户才能建立,更新和删除代码段。

REST框架包括许多权限类,咱们可使用它们来限制谁能够访问给定的视图。在这种状况下,咱们正在寻找的是IsAuthenticatedOrReadOnly,这将确保通过身份验证的请求得到读写访问权限,未经身份验证的请求将得到只读访问权限。

首先在视图模块中添加如下导入

from rest_framework import permissions

  

接着,下面的属性添加到SnippetListSnippetDetail视图类。

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

  

添加登陆到Browsable API

若是您打开浏览器并导航到目前可浏览的API,那么您将发现没法再建立新的代码段。为了作到这一点,咱们须要可以以用户身份登陆。

咱们能够经过编辑项目级urls.py文件中的URLconf来添加可浏览API使用的登陆视图。

在文件顶部添加如下导入:

from django.conf.urls import include

  

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

urlpatterns += [
    url(r'^api-auth/', include('rest_framework.urls',
                               namespace='rest_framework')),
]

  

r'^api-auth/'模式的一部分实际上能够是您要使用的任何URL。惟一的限制是所包含的URL必须使用'rest_framework'命名空间。在Django 1.9+中,REST框架将设置命名空间,所以您能够将其删除。

如今,若是再次打开浏览器并刷新页面,您将在页面右上角看到一个“登陆”连接。若是您以您以前建立的用户身份登陆,则能够再次建立代码段。

建立几个代码片断后,导航到“/ users /”端点,并注意到该表示包含每一个用户的“片断”字段中与每一个用户相关联的代码段的列表。

对象级权限

咱们但愿全部的代码片断均可以被任何人看到,但也要确保只有建立代码段的用户才能更新或删除它。

要作到这一点,咱们将须要建立一个自定义权限。

在片断应用中,建立一个新文件, permissions.py

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.owner == request.user

  

如今,咱们能够经过编辑视图类中的permission_classes属性将该自定义权限添加到咱们的代码段实例端点SnippetDetail

permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly,)

  

确保也导入IsOwnerOrReadOnly类。

from snippets.permissions import IsOwnerOrReadOnly

  

如今,若是再次打开浏览器,您会发现若是您以与建立代码段相同的用户身份登陆,“DELETE”和“PUT”操做只会显示在代码段实例端点上。

使用API进行身份验证

由于咱们如今有一组API的权限,若是咱们要编辑任何片断,咱们须要验证咱们的请求。咱们尚未设置任何身份验证类,因此默认值如今被应用,哪些是SessionAuthenticationBasicAuthentication

当咱们经过Web浏览器与API进行交互时,咱们能够登陆,而后浏览器会话将为请求提供所需的身份验证。

若是咱们以编程方式与API交互,咱们须要在每一个请求上显式提供身份验证凭据。

若是咱们尝试建立一个没有验证的代码段,咱们会收到一个错误:

http POST http://127.0.0.1:8000/snippets/ code="print 123"

{
    "detail": "Authentication credentials were not provided."
}

  

咱们能够经过包括咱们以前建立的一个用户的用户名和密码来成功提出请求。

http -a tom:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"

{
    "id": 1,
    "owner": "tom",
    "title": "foo",
    "code": "print 789",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

  

概要

咱们如今已经在咱们的Web API上得到了一个至关精细的权限,并为系统的用户和他们建立的代码段提供了终点。

在本教程的第5部分中,咱们将介绍如何经过为突出显示的片断建立一个HTML端点来将全部内容联结在一块儿,并经过为系统中的关系使用超连接来提升API的凝聚力。

Django REST FrameWork中文文档目录:

相关文章
相关标签/搜索