1. 程式人生 > >Django REST framework 第四章 Authentication

Django REST framework 第四章 Authentication

urn else cati pro 只讀權限 view tput 圖標 你會

到目前為止,撰寫的API沒有任何限制關於誰能更新、刪除snippet. 我們更想要一些高級行為來確保:

1、代碼段總是跟創建者有關聯

2、只要認證通過的用戶才能創建

3、只有創建者有權限更新或者刪除

4、沒有認證的請求應該有且只有完全的只讀權限

Adding information to our model

我們打算在Snippet模型類上做一些改變。首先,添加一些字段,其中之一用來代表創建這個code的用戶。其他的字段將用於存儲代碼中突出顯示的HTML表示形式。

添加下面兩個字段到Snippet類在models.py.

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

現在需要往model類裏面添加一個save方法:

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類的內部.

這個字段做了些很有趣的事情。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不帶驗證,將會得到報錯:

技術分享圖片

帶上認證憑據:

技術分享圖片

Django REST framework 第四章 Authentication