Django drf 認證

2020-01-22 11:45 更新

認證

身份驗證功能需要可插拔?!?Jacob Kaplan-Moss, "REST worst practices"

身份驗證是將傳入請求與一組標識憑據(jù)(例如請求來自的用戶或其簽名的令牌)相關(guān)聯(lián)的機制。然后,權(quán)限 和 限制 可以使用這些憑據(jù)來確定是否應(yīng)允許該請求。

REST framework 提供了一些開箱即用的身份驗證方案,并且還允許你實現(xiàn)自定義方案。

驗證始終在視圖的最開始進行,在執(zhí)行權(quán)限和限制檢查之前以及允許任何其他代碼繼續(xù)執(zhí)行之前。

request.user 屬性通常被設(shè)置為contrib.auth 包中 User 類的一個實例。

request.auth 屬性用于任何其他身份驗證信息,例如,它可以用于表示請求簽名的身份驗證令牌。

注意: 不要忘了認證本身不會允許或拒絕傳入的請求,它只是簡單識別請求攜帶的憑證。

如何確定身份驗證

認證方案總是被定義為一個類的列表。REST framework 將嘗試使用列表中的每個類進行身份驗證,并使用成功完成驗證的第一個類的返回值設(shè)置 request.user 和request.auth。

如果沒有類進行驗證,request.user 將被設(shè)置成 django.contrib.auth.models.AnonymousUser的實例,request.auth 將被設(shè)置成None。

未認證請求的request.user 和 request.auth 的值可以使用 UNAUTHENTICATED_USER和UNAUTHENTICATED_TOKEN 設(shè)置進行修改。

設(shè)置認證方案

可以使用 DEFAULT_AUTHENTICATION_CLASSES 設(shè)置全局的默認身份驗證方案。比如:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    )
}

你還可以使用基于APIView類視圖的方式,在每個view或每個viewset基礎(chǔ)上設(shè)置身份驗證方案。

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    authentication_classes = (SessionAuthentication, BasicAuthentication)
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'user': unicode(request.user),  # `django.contrib.auth.User` 實例。
            'auth': unicode(request.auth),  # None
        }
        return Response(content)

或者,如果你使用基于函數(shù)的視圖,那就使用@api_view裝飾器。

@api_view(['GET'])
@authentication_classes((SessionAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
def example_view(request, format=None):
    content = {
        'user': unicode(request.user),  # `django.contrib.auth.User` 實例。
        'auth': unicode(request.auth),  # None
    }
    return Response(content)

未認證和禁止的響應(yīng)

當未經(jīng)身份驗證的請求被拒絕時,有下面兩種不同的錯誤代碼可使用。

HTTP 401 響應(yīng)必須始終包括一個WWW-Authenticate頭,指示客戶端如何進行身份驗證。 HTTP 403響應(yīng)不包括WWW-Authenticate。

具體使用哪種響應(yīng)取決于認證方案。雖然可以使用多種認證方案,但是僅可以使用一種方案來確定響應(yīng)的類型。在確定響應(yīng)類型時,將使用視圖上設(shè)置的第一個認證類。

注意,當一個請求通過了驗證但是被拒絕執(zhí)行請求的權(quán)限時,不管認證方案是什么,都要使用 403 Permission Denied 響應(yīng)。

Apache mod_wsgi 具體配置

注意,如果使用 Apache using mod_wsgi部署,認證頭默認不會傳遞給WSGI應(yīng)用程序,它假定由Apache處理認證,而不是在應(yīng)用層面處理。

如果你正在部署到Apache,并且使用任何non-session的身份驗證,則需要顯式配置mod_wsgi才能將所需的頭文件傳遞給應(yīng)用程序。這可以通過在適當?shù)纳舷挛闹兄付╓SGIPassAuthorization指令并將其設(shè)置為'On'來完成。

# 這可能會在服務(wù)器配置,虛擬主機,目錄或.htaccess
WSGIPassAuthorization On

API 參考

BasicAuthentication

此認證方案使用HTTP 基本認證,針對用戶的用戶名和密碼進行認證?;菊J證通常只適用于測試。

如果認證成功 BasicAuthentication 提供以下信息。

  • request.user 將是一個 Django User 實例。
  • request.auth 將是 None。

那些被拒絕的未經(jīng)身份驗證的請求會返回使用適當WWW-Authenticate標頭的HTTP 401 Unauthorized響應(yīng)。例如:

WWW-Authenticate: Basic realm="api"

注意: 如果你在生產(chǎn)中使用BasicAuthentication,那么你必須確保你的API僅在https中可用。你還應(yīng)確保你的API客戶端始終在登錄時重新請求用戶名和密碼,并且不會將這些詳細信息存儲到持久存儲中。

TokenAuthentication

該認證方案使用簡單的基于Token的HTTP認證方案。Token認證適用于客戶端 - 服務(wù)器設(shè)置,如本地桌面和移動客戶端。

要使用TokenAuthentication方案,你需要配置認證類 以便包含TokenAuthentication,另外在INSTALLED_APPS設(shè)置中還需要包含rest_framework.authtoken:

INSTALLED_APPS = (
    ...
    'rest_framework.authtoken'
)

注意: 確保在修改設(shè)置后運行一下manage.py migrate。rest_framework.authtoken app 會提交一些Django數(shù)據(jù)庫遷移操作。

你還需要為你的用戶創(chuàng)建令牌。

from rest_framework.authtoken.models import Token

token = Token.objects.create(user=...)
print token.key

對客戶端進行身份驗證,token需要包含在 AuthorizationHTTP頭中。密鑰應(yīng)該是以字符串"Token"為前綴,以空格分割的兩個字符串。例如:

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

注意: 如果你想在HTTP頭中使用其他的關(guān)鍵字,比如Bearer,只需要繼承TokenAuthentication類并設(shè)置 keyword類變量。

如果認證成功,TokenAuthentication 提供以下認證信息:

  • request.user 將是一個Django User 實例。
  • request.auth 將是一個rest_framework.authtoken.models.Token 實例。

那些被拒絕的未經(jīng)身份驗證的請求會返回使用適當WWW-Authenticate標頭的HTTP 401 Unauthorized響應(yīng)。例如:

WWW-Authenticate: Token

命令行工具curl 可用于測試基于Token認證的API,例如:

curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'

注意: 如果你在生產(chǎn)環(huán)境下使用TokenAuthentication認證,你必須確保你的API僅在https可用。

生成Tokens

通過使用信號

如果你希望每個用戶擁有自動生成的令牌,你可以簡單地捕獲用戶的post_save信號。

from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

請注意,你需要確保將此代碼段放置在已安裝的models.py模塊或Django在啟動時導入的其他位置。

如果你已經(jīng)創(chuàng)建了一些用戶,則可以如下所示為所有現(xiàn)有用戶生成令牌:

from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token

for user in User.objects.all():
    Token.objects.get_or_create(user=user)
通過暴露 api 端點

當使用TokenAuthentication時,你可能希望為客戶端提供一個獲取給定用戶名和密碼的令牌的機制。 REST framework 提供了一個內(nèi)置的視圖來提供這個功能。要使用它,需要將 obtain_auth_token 視圖添加到你的URLconf:

from rest_framework.authtoken import views
urlpatterns += [
    url(r'^api-token-auth/', views.obtain_auth_token)
]

注意URL正則匹配模式那里可以是你想要使用的任何內(nèi)容。

當使用form表單或JSON將有效的username和password字段POST提交到視圖時,obtain_auth_token視圖將返回JSON響應(yīng):

{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }

請注意,默認的obtain_auth_token視圖顯式使用JSON請求和響應(yīng),而不是使用settings中配置的默認渲染器和解析器類。如果需要自定義版本的obtain_auth_token視圖,可以通過重寫ObtainAuthToken類,并在url conf中使用它來實現(xiàn)。

默認情況下,沒有權(quán)限或限制應(yīng)用于obtain_auth_token視圖。如果你希望應(yīng)用限制,則需要重寫視圖類,并使用throttle_classes屬性包含它們。

With Django admin

也可以通過管理界面手動創(chuàng)建令牌。如果你使用的是大型用戶群,我們建議你動態(tài)修改TokenAdmin類,以根據(jù)你的需要進行自定義,更具體地說,將user字段聲明為raw_field。

your_app/admin.py:

from rest_framework.authtoken.admin import TokenAdmin

TokenAdmin.raw_id_fields = ('user',)

Session認證

此認證方案使用Django的默認session后端進行身份驗證。Session身份驗證適用于與你的網(wǎng)站在相同的Session環(huán)境中運行的AJAX客戶端。

如果成功驗證,SessionAuthentication 提供以下憑據(jù)。

  • request.user 是一個 Django User 實例。
  • request.auth 是 None。

那些被拒絕的未經(jīng)身份驗證的請求會返回HTTP 403 Forbidden響應(yīng)。

如果你正在使用帶有SessionAuthentication的AJAX樣式的API,你需要確保任何"任何"不安全的HTTP方法調(diào)用(如:PUT, PATCH, POST or DELETE請求)都包含有效的CSRF token。有關(guān)詳細信息,請參閱Django CSRF 文檔。

警告:在創(chuàng)建登陸頁面時,始終要使用Django的標準登陸視圖。這樣才能確保你的登陸視圖被正確的認證保護。

由于需要同時支持session和non-session非會話身份驗證,REST框架中的CSRF驗證與標準Django中的工作方式略有不同。這意味著只有經(jīng)過身份驗證的請求需要CSRF令牌,匿名請求可能不會發(fā)送CSRF令牌tokens。此行為不適用于始終需要使用CSRF驗證的登錄視圖。

自定義認證

要實現(xiàn)自定義的認證方案,要繼承BaseAuthentication類并且重寫.authenticate(self, request) 方法。如果認證成功,該方法應(yīng)返回(user, auth)的二元元組,否則返回None。

在某些情況下,你可能不想返回None,而是希望從.authenticate()方法拋出AuthenticationFailed異常。

通常你應(yīng)該采取的方法是:

  • 如果不嘗試驗證,返回None。還將檢查任何其他正在使用的身份驗證方案。
  • 如果嘗試驗證但失敗,則拋出AuthenticationFailed異常。無論任何權(quán)限檢查也不檢查任何其他身份驗證方案,立即返回錯誤響應(yīng)。

你也可以重寫.authenticate_header(self, request)方法。如果實現(xiàn)該方法,則應(yīng)返回一個字符串,該字符串將用作HTTP 401 Unauthorized響應(yīng)中的WWW-Authenticate頭的值。

如果.authenticate_header()方法未被重寫,則認證方案將在未驗證的請求被拒絕訪問時返回HTTP 403 Forbidden響應(yīng)。

示例

以下示例將以自定義請求標頭中名稱為'X_USERNAME'提供的用戶名作為用戶對任何傳入請求進行身份驗證。

from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

class ExampleAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        username = request.META.get('X_USERNAME')
        if not username:
            return None

        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            raise exceptions.AuthenticationFailed('No such user')

        return (user, None)

第三方包

以下第三方包都是可用的。

Django OAuth Toolkit

Django OAuth Toolkit 包提供了OAuth 2.0 認證支持,并且兼容Python 2.7和Python 3.3+。這個包使用優(yōu)秀的OAuthLib,由Evonove維護。該軟件包有很完善的文檔,并得到很好的支持,目前是我們推薦使用的OAuth 2.0支持軟件包。

安裝和配置

使用pip安裝。

pip install django-oauth-toolkit

把這個包添加到你的INSTALLED_APPS中,并且修改你的REST framework設(shè)置。

INSTALLED_APPS = (
    ...
    'oauth2_provider',
)

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.ext.rest_framework.OAuth2Authentication',
    )
}

更多詳情請參閱Django REST framework - Getting started文檔。

Django REST framework OAuth

Django REST framework OAuth包提供OAuth1和OAuth2支持。

這個軟件包以前直接包含在REST framework中,但現(xiàn)在已被作為第三方軟件包支持和維護。

安裝和配置

使用pip進行安裝。

pip install djangorestframework-oauth

更多配置和使用信息請查閱Django REST framework OAuth文檔中的authenticationpermissions

Digest Authentication

HTTP摘要認證是一種廣泛實現(xiàn)的方案,旨在替代HTTP基本認證,并提供簡單的加密認證機制。Juan Riaza維護著djangorestframework-digestauth為REST framework提供了HTTP摘要認證支持。

Django OAuth2 Consumer

Rediker SoftwareDjango OAuth2 Consumer是另一個為REST框架提供OAuth 2.0 support for REST framework的軟件包。該包包含tokens范圍限制權(quán)限,允許對你的API進行更細粒度的訪問。

JSON Web Token Authentication

JSON Web Token是一種相當新的標準,可用于基于token的身份驗證。與內(nèi)置的TokenAuthentication方案不同,JWT身份驗證不需要使用數(shù)據(jù)庫來驗證令牌。Blimp維護djangorestframework-jwt軟件包,它提供了一個JWT Authentication類以及一個機制,客戶端獲得一個給定用戶名和密碼的JWT。

Hawk HTTP Authentication

HawkREST庫基于Mohawk庫,讓你可以在API中使用Hawk簽名的請求和響應(yīng)。Hawk讓雙方使用共享密鑰簽名的消息彼此安全地進行通信。它基于HTTP MAC access authentication訪問認證(它基于OAuth 1.0的部分)。

HTTP Signature Authentication

HTTP簽名(目前為IETF草案)提供了一種實現(xiàn)HTTP消息的源認證和消息完整性的方法。與Amazon的HTTP簽名方案類似,許多服務(wù)使用它,它允許無狀態(tài)的每個請求的身份驗證。Elvio Toccalino維護了djangorestframework-httpsignature包,提供了一個易于使用的HTTP簽名身份驗證機制。

Djoser

Djoser庫提供一組視圖來處理基本操作,如注冊,登錄,注銷,密碼重置和帳戶激活。該包使用自定義用戶模型,它使用基于token的身份驗證。這是一個可以使用REST實現(xiàn)的Django認證系統(tǒng)。

django-rest-auth

Django-rest-auth庫提供了一組REST API端點,用于注冊,身份驗證(包括社交媒體身份驗證),密碼重置,檢索和更新用戶詳細信息等。有了這些API端點之后,你的客戶端應(yīng)用程序(如AngularJS,iOS,Android和其他)可以通過REST API獨立通信到Django后端站點,以進行用戶管理。

django-rest-framework-social-oauth2

Django-rest-framework-social-oauth2庫提供了一種將社交插件(facebook,twitter,google等)集成到你的身份驗證系統(tǒng)和簡單的oauth2設(shè)置的簡單方法。使用這個庫,你將能夠根據(jù)外部token(例如,F(xiàn)acebook訪問token)對用戶進行身份驗證,將這些令牌轉(zhuǎn)換為“內(nèi)部”oauth2 tokens,并使用和生成oauth2 tokens來驗證用戶。

django-rest-knox

Django-rest-knox庫提供了模型和視圖,以比內(nèi)置的TokenAuthentication方案更安全和可擴展的方式來處理基于token的身份驗證 - 使用單頁面應(yīng)用程序和移動客戶端能夠一起。它為每個客戶端提供tokens,以及在提供一些其他身份驗證(通常是基本身份驗證)時生成tokens,刪除token(提供服務(wù)器強制注銷)和刪除所有tokens(注銷用戶登錄的所有客戶端)的視圖。


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號