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不帶驗證,將會獲得報錯:

帶上認證憑據:

相關文章
相關標籤/搜索