Django REST framework 第四章 Authentication

到目前为止,撰写的API没有任何限制关于谁能更新、删除snippet. 咱们更想要一些高级行为来确保:html

一、代码段老是跟建立者有关联python

二、只要认证经过的用户才能建立sql

三、只有建立者有权限更新或者删除数据库

四、没有认证的请求应该有且只有彻底的只读权限django

 

Adding information to our model

咱们打算在Snippet模型类上作一些改变。首先,添加一些字段,其中之一用来表明建立这个code的用户。其余的字段将用于存储代码中突出显示的HTML表示形式。api

添加下面两个字段到Snippet类在models.py.浏览器

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

咱们还须要确保当模型被保存时,咱们使用pygments代码突出显示库填充突出显示的字段。此外还须要导入些其余的:session

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

如今须要往model类里面添加一个save方法:app

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 = 'table' if self.linenos else False
    options = {'title': self.title} if self.title else {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                              full=True, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super(Snippet, self).save(*args, **kwargs)

作好上面的操做后,须要同步数据库测试

shuais-MacBook-Pro:TestApp dandyzhang$ rm -f db.sqlite3
shuais-MacBook-Pro:TestApp dandyzhang$ rm -r app01/migrations
shuais-MacBook-Pro:TestApp dandyzhang$ python3 manage.py makemigrations
shuais-MacBook-Pro:TestApp dandyzhang$ python3 manage.py migrate

为了测试API,还须要建立一下超级用户:

shuais-MacBook-Pro:TestApp dandyzhang$ python3 manage.py createsuperuser

 

Adding endpoints for our User models

如今咱们已经有一些工做的用户了,还须要添加这些用户的表示到API中。

在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')

snippets在 User model上是一种反转关系,在继承ModelSerializer类不能使用默认值。因此须要为它添加一个明确的字段

一样,也须要在views.py文件内添加一些东西。咱们更倾向于为用户表示使用只读权限,因此咱们将使用ListAPIViewRetrieveAPIView generic CBV.

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 app01.serializers import UserSerializer

最后,咱们须要把这些视图添加进API,经过url设置,在urls.py文件中

    path('users/', views.UserList.as_view()),
    path('users/<int:pk>/', views.UserDetail.as_view()),

 

Associating Snippets with Users

如今,若是咱们建立snippet,会发现没有办法经过snippet实例关联到建立的用户。用户不是做为序列化表示的一部分发送的,而是即将到来的请求的属性。

解决这个问题的方式是重写一个.perform_create()方法在views里面,它容许咱们修改管理实例如何保存,处理传入请求或者被请求URL的任何信息

SnippetList视图类添加以下的方法:

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

一个额外添加的owner字段如今将会被serializer里面的create方法经过,跟请求里面的验证数据一块儿。

 

Updating our serializer

如今snippets和用户的关联建好了,更新一下SnippetSerializer来反应它。在serializers.py文件添加:

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

注意将它添加在Meta类内部的字段列表中.

class SnippetSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')

    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')

 

这个字段作了些颇有趣的事情。source参数控制一种属性用来跟某个字段关联对应,能够指向序列化实例的任何属性。它也能够采用上面所显示的实例的表示法,将会遍历给定的属性,跟Django的模版语言很相似。

咱们刚刚添加的这个字段是一个非类型化的ReadOnlyField类,与其余类型字段相反,好比CharFieldBooleanField等...非类型话的ReadOnlyField老是只读的,并将用于序列化表示,可是在反序列化的时候不能被用来更新模型实例,也能够用CharField(read_only=True)

 

Adding required permissions to views

如今snippet已经跟用户有联系了,咱们想肯定只有经过验证的用户能够建立,更新,删除snippet。

REST framework包含了一串权限类供用来限制谁能访问一个给定的视图。在这里,咱们想要寻找的是IsAuthenticatedOrReadOnly这个类用来确保经过验证的请求获取到读写权限,没有经过验证的请求得到只读权限。

首先在views里面导入模块

from rest_framework import permissions

而后添加下面的属性到SnippetList和SnippetDetail两个视图类中。

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

 

 

Adding login to Browable API

若是你打开浏览器,导航到了可浏览的API,你会发现你不能再建立新的spnippet了。为了能这样作,须要先登录。

咱们能够再根目录的urls文件内加入下面的路由,它包含可浏览的API的登录和登出。

    path('api/', include('rest_framework.urls', namespace='rest_framework')),

路由的名称能够自定义。

如今打开浏览器,你会在网页的右上角看到login的图标。若是你用以前建立的用户登录了,你就能够再一次建立snippet了。

建立好一些snippet后,你就能够在子路由users下面查看到

 

 

 

Object level permissions 

咱们想让全部的snippet被任何人看到,但必须保证只有建立的人才能够增删改。

想要这么作,须要建立一个定制化的权限。建立一个新的文件在app内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

如今能够添加自定义的权限到snippet实例终端,经过编辑在SnippetDetail视图类里面的permission_classes属性

from app01.permissions import IsOwnerOrReadOnly  # 先导入 

permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly,)

如今从新运行一下此项目,你会发现delete和put按钮出如今你建立的一个snippet实例的终端。

 

 

 

Authenticating with the API

由于如今已经有一批权限在API上,若是须要编辑任何的snippet须要认证请求。可是咱们尚未设置任何的认证类,因此此时是使用的默认的类SessionAuthenticationBasicAuthentication

当咱们经过浏览器跟API进行交互,咱们能够登录,而后浏览器的session会提供必要的认证给请求。若是咱们以变成的方式跟API交互,就须要提供明确的认证凭据在每一次请求上。若是尝试建立一个新的snippet不带验证,将会获得报错:

带上认证凭据:

相关文章
相关标签/搜索