国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

Django drf 認(rèn)證和權(quán)限

2020-01-22 11:22 更新

目前,我們的API對(duì)誰(shuí)可以編輯或刪除代碼段沒(méi)有任何限制。我們希望有更高級(jí)的行為,以確保:

  • 代碼片段始終與創(chuàng)建者相關(guān)聯(lián)。
  • 只有通過(guò)身份驗(yàn)證的用戶可以創(chuàng)建片段。
  • 只有代碼片段的創(chuàng)建者可以更新或刪除它。
  • 未經(jīng)身份驗(yàn)證的請(qǐng)求應(yīng)具有完全只讀訪問(wèn)權(quán)限。

在我們的模型(model)中添加信息

我們將對(duì)我們的Snippet模型類(lèi)進(jìn)行幾次更改。首先,我們添加幾個(gè)字段。其中一個(gè)字段將用于表示創(chuàng)建代碼段的用戶,另一個(gè)字段將用于存儲(chǔ)代碼的高亮顯示的HTML內(nèi)容。

將以下兩個(gè)字段添加到models.py文件中的Snippet模型中。

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

我們還需要確保在保存模型時(shí),使用pygments代碼高亮顯示庫(kù)填充要高亮顯示的字段。

我們需要導(dǎo)入額外的模塊:

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

現(xiàn)在我們可以在我們的模型類(lèi)中添加一個(gè).save()方法:

def save(self, *args, **kwargs):
    """
    使用`pygments`庫(kù)創(chuàng)建一個(gè)高亮顯示的HTML表示代碼段。
    """
    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)

完成這些工作后,我們需要更新我們的數(shù)據(jù)庫(kù)表。 通常這種情況我們會(huì)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)遷移(migration)來(lái)實(shí)現(xiàn)這一點(diǎn),但現(xiàn)在我們只是個(gè)教程示例,所以我們選擇直接刪除數(shù)據(jù)庫(kù)并重新開(kāi)始。

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

你可能還需要?jiǎng)?chuàng)建幾個(gè)不同的用戶,以用于測(cè)試API。最快的方法是使用createsuperuser命令。

python manage.py createsuperuser

為我們的用戶模型添加路徑

現(xiàn)在我們已經(jīng)創(chuàng)建了一些用戶,我們最好在API中添加這些用戶的表示。創(chuàng)建一個(gè)新的序列化器非常簡(jiǎn)單,在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')

因?yàn)?snippets' 在用戶模型中是一個(gè)反向關(guān)聯(lián)關(guān)系。在使用 ModelSerializer 類(lèi)時(shí)它默認(rèn)不會(huì)被包含,所以我們需要為它添加一個(gè)顯式字段。

我們還會(huì)在views.py中添加幾個(gè)視圖。我們只想將用戶展示為只讀視圖,因此我們將使用ListAPIView和RetrieveAPIView通用的基于類(lèi)的視圖。

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

確保導(dǎo)入了UserSerializer類(lèi)

from snippets.serializers import UserSerializer

最后,我們需要通過(guò)在URL conf中引用它們來(lái)將這些視圖添加到API中。將以下內(nèi)容添加到urls.py文件的patterns中。

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

將Snippet和用戶關(guān)聯(lián)

現(xiàn)在,如果我們創(chuàng)建了一個(gè)代碼片段,并不能將創(chuàng)建該代碼片段的用戶與代碼段實(shí)例相關(guān)聯(lián)。用戶不是作為序列化表示的一部分發(fā)送的,而是作為傳入請(qǐng)求的屬性。(譯者注:user不在傳過(guò)來(lái)的數(shù)據(jù)中,而是通過(guò)request.user獲得)

我們處理的方式是在我們的代碼片段視圖中重寫(xiě)一個(gè).perform_create()方法,這樣我們可以修改實(shí)例保存的方法,并處理傳入請(qǐng)求或請(qǐng)求URL中隱含的任何信息。

在SnippetList視圖類(lèi)中,添加以下方法:

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

我們的序列化器的create()方法現(xiàn)在將被傳遞一個(gè)附加的'owner'字段以及來(lái)自請(qǐng)求的驗(yàn)證數(shù)據(jù)。

更新我們的序列化器

現(xiàn)在,這些代碼片段和創(chuàng)建它們的用戶相關(guān)聯(lián),讓我們更新我們的SnippetSerializer來(lái)體現(xiàn)這個(gè)關(guān)聯(lián)關(guān)系。將以下字段添加到serializers.py中的序列化器定義: Add the following field to the serializer definition in serializers.py:

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

注意:確保你還將'owner',添加到內(nèi)部Meta類(lèi)的字段列表中。

這個(gè)字段非常有趣。source參數(shù)控制哪個(gè)屬性用于填充字段,并且可以指向序列化實(shí)例上的任何屬性。它也可以采用如上所示點(diǎn)加下劃線的方式,在這種情況下,它將以與Django模板語(yǔ)言一起使用的相似方式遍歷給定的屬性。

我們添加的字段是無(wú)類(lèi)型的ReadOnlyField類(lèi),區(qū)別于其他類(lèi)型的字段(如CharField,BooleanField等)。無(wú)類(lèi)型的ReadOnlyField始終是只讀的,只能用于序列化表示,不能用于在反序列化時(shí)更新模型實(shí)例。我們也可以在這里使用CharField(read_only=True)。

添加視圖所需的權(quán)限

現(xiàn)在,代碼片段與用戶是相關(guān)聯(lián)的,我們希望確保只有經(jīng)過(guò)身份驗(yàn)證的用戶才能創(chuàng)建,更新和刪除代碼片段。

REST框架包括許多權(quán)限類(lèi),我們可以使用這些權(quán)限類(lèi)來(lái)限制誰(shuí)可以訪問(wèn)給定的視圖。 在這種情況下,我們需要的是IsAuthenticatedOrReadOnly類(lèi),這將確保經(jīng)過(guò)身份驗(yàn)證的請(qǐng)求獲得讀寫(xiě)訪問(wèn)權(quán)限,未經(jīng)身份驗(yàn)證的請(qǐng)求將獲得只讀訪問(wèn)權(quán)限。

首先要在視圖模塊中導(dǎo)入以下內(nèi)容

from rest_framework import permissions

然后,將以下屬性添加到SnippetList和SnippetDetail視圖類(lèi)中。

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

給Browsable API添加登陸

如果你打開(kāi)瀏覽器并瀏覽我們的API,那么你會(huì)發(fā)現(xiàn)不能創(chuàng)建新的代碼片段。只有登陸用戶才能創(chuàng)建新的代碼片段。

我們可以通過(guò)編輯項(xiàng)目級(jí)別的urls.py文件中的URLconf來(lái)添加可瀏覽的API使用的登錄視圖。

在文件頂部添加以下導(dǎo)入:

from django.conf.urls import include

而且,在文件末尾添加一個(gè)模式(pattern)以包括可瀏覽的API的登錄和注銷(xiāo)視圖。

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

模式的r'^api-auth/'部分實(shí)際上可以是你要使用的任何URL。唯一的限制是包含的URL必須使用'rest_framework'命名空間。在Django 1.9以上的版本中,REST框架將設(shè)置命名空間,因此你可以將其刪除。

現(xiàn)在,如果你再次打開(kāi)瀏覽器并刷新頁(yè)面,你將在頁(yè)面右上角看到一個(gè)“登錄”鏈接。如果你用早期創(chuàng)建的用戶登錄,就可以再次創(chuàng)建代碼片段。

一旦你創(chuàng)建了一些代碼片段后,在'/users/'路徑下你會(huì)注意到每個(gè)用戶的'snippets'字段都包含與每個(gè)用戶相關(guān)聯(lián)的代碼片段的列表。

對(duì)象級(jí)別的權(quán)限

我們希望所有的代碼片段都可以被任何人看到,但也要確保只有創(chuàng)建代碼片段的用戶才能更新或刪除它。

為此,我們將需要?jiǎng)?chuàng)建一個(gè)自定義權(quán)限。

在snippets app中,創(chuàng)建一個(gè)新文件permissions.py。

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    自定義權(quán)限只允許對(duì)象的所有者編輯它。
    """

    def has_object_permission(self, request, view, obj):
        # 讀取權(quán)限允許任何請(qǐng)求,
        # 所以我們總是允許GET,HEAD或OPTIONS請(qǐng)求。
        if request.method in permissions.SAFE_METHODS:
            return True

        # 只有該snippet的所有者才允許寫(xiě)權(quán)限。
        return obj.owner == request.user

現(xiàn)在,我們可以通過(guò)在SnippetDetail視圖類(lèi)中編輯permission_classes屬性將該自定義權(quán)限添加到我們的代碼片段實(shí)例路徑:

permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly,)

確保要先導(dǎo)入IsOwnerOrReadOnly類(lèi)。

from snippets.permissions import IsOwnerOrReadOnly

現(xiàn)在,如果再次打開(kāi)瀏覽器,你會(huì)發(fā)現(xiàn)如果你以代碼片段創(chuàng)建者的身份登錄的話,“DELETE”和“PUT”操作才會(huì)顯示在代碼片段實(shí)例路徑上。

使用API??進(jìn)行身份驗(yàn)證

現(xiàn)在因?yàn)槲覀冊(cè)贏PI上有一組權(quán)限,如果我們要編輯任何代碼片段,我們都需要驗(yàn)證我們的請(qǐng)求。我們還沒(méi)有設(shè)置任何身份驗(yàn)證類(lèi),所以應(yīng)用的是默認(rèn)的SessionAuthentication和BasicAuthentication。

當(dāng)我們通過(guò)Web瀏覽器與API進(jìn)行交互時(shí),我們可以登錄,然后瀏覽器會(huì)話將為請(qǐng)求提供所需的身份驗(yàn)證。

如果我們?cè)诖a中與API交互,我們需要在每次請(qǐng)求上顯式提供身份驗(yàn)證憑據(jù)。

如果我們通過(guò)沒(méi)有驗(yàn)證就嘗試創(chuàng)建一個(gè)代碼片段,我們會(huì)像下面展示的那樣收到報(bào)錯(cuò):

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

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

我們可以通過(guò)加上我們之前創(chuàng)建的一個(gè)用戶的用戶名和密碼來(lái)成功創(chuàng)建:

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

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

總結(jié)

我們現(xiàn)在已經(jīng)在我們的Web API上獲得了相當(dāng)精細(xì)的一組權(quán)限控制,并為系統(tǒng)的用戶和他們創(chuàng)建的代碼片段提供了API路徑。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)