身份驗證是將傳入請求與一組識別憑證(例如請求的用戶或其簽名的令牌)相關聯的機制。而後,權限和限制策略可使用這些憑據來肯定請求是否應該被容許。python
REST framework 提供了許多開箱即用的身份驗證方案,同時也容許你實施自定義方案。nginx
身份驗證始終在視圖的開始處運行,在執行權限和限制檢查以前,在容許繼續執行任何其餘代碼以前。git
request.user
屬性一般會設置爲 contrib.auth
包的 User
類的一個實例。github
request.auth
屬性用於其餘身份驗證信息,例如,它能夠用來表示請求已簽名的身份驗證令牌。數據庫
注意: 不要忘記, 身份驗證自己不會(容許或不容許)傳入的請求,它只是標識請求的憑據。apache
認證方案老是被定義爲一個類的列表。 REST framework 將嘗試使用列表中的每一個類進行認證,並將使用成功認證的第一個類的返回值來設置 request.user
和 request.auth
。django
若是沒有類進行身份驗證,則將 request.user
設置爲 django.contrib.auth.models.AnonymousUser
的實例,並將 request.auth
設置爲 None
.後端
可使用 UNAUTHENTICATED_USER
和 UNAUTHENTICATED_TOKEN
設置修改未經身份驗證的請求的 request.user
和 request.auth
的值。api
默認的認證方案可使用 DEFAULT_AUTHENTICATION_CLASSES
setting 全局設置。例如。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
複製代碼
您還可使用基於 APIView
類的視圖,在每一個視圖或每一個視圖集的基礎上設置身份驗證方案。
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` instance.
'auth': unicode(request.auth), # None
}
return Response(content)
複製代碼
或者,若是您將 @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` instance.
'auth': unicode(request.auth), # None
}
return Response(content)
複製代碼
當未經身份驗證的請求被拒絕時,有兩種不一樣的錯誤代碼多是合適的。
HTTP 401 響應必須始終包含 WWW-Authenticate
header,該 header 指示客戶端如何進行身份驗證。 HTTP 403 響應不包含 WWW-Authenticate
header。
將使用哪一種響應取決於認證方案。儘管可能正在使用多種認證方案,但只能使用一種方案來肯定響應的類型。 在肯定響應類型時使用視圖上設置的第一個認證類。
請注意,當請求能夠成功進行身份驗證時,仍然可能會由於權限而被拒絕,在這種狀況下,將始終使用 403 Permission Denied
響應,而無論身份驗證方案如何。
請注意,若是使用 mod_wsgi 部署到 Apache,受權 header 默認狀況下不會傳遞到 WSGI 應用程序,由於它假定認證將由 Apache 處理,而不是在應用程序級別處理。
若是您正在部署到 Apache 並使用任何基於非會話的身份驗證,則須要明確配置 mod_wsgi 以將所需的 headers 傳遞給應用程序。這能夠經過在適當的上下文中指定 WSGIPassAuthorization
指令並將其設置爲 'On'
來完成。
# this can go in either server config, virtual host, directory or .htaccess
WSGIPassAuthorization On
複製代碼
該認證方案使用 HTTP Basic Authentication,並根據用戶的用戶名和密碼進行簽名。Basic Authentication 一般只適用於測試。
若是成功經過身份驗證,BasicAuthentication
將提供如下憑據。
request.user
是一個 Django User
實力.request.auth
是 None
.未經身份驗證的響應被拒絕將致使 HTTP 401 Unauthorized
的響應和相應的 WWW-Authenticate header。例如:
WWW-Authenticate: Basic realm="api"
複製代碼
注意: 若是您在生產環境中使用 BasicAuthentication
,則必須確保您的 API 僅可經過 https
訪問。您還應該確保您的 API 客戶端將始終在登陸時從新請求用戶名和密碼,而且永遠不會將這些詳細信息存儲到持久化存儲中。
此認證方案使用簡單的基於令牌的 HTTP 認證方案。令牌身份驗證適用於 client-server 架構,例如本機桌面和移動客戶端。
要使用 TokenAuthentication
方案,您須要將認證類配置爲包含 TokenAuthentication
,並在 INSTALLED_APPS
設置中另外包含 rest_framework.authtoken
:
INSTALLED_APPS = (
...
'rest_framework.authtoken'
)
複製代碼
注意: 確保在更改設置後運行 manage.py migrate
。 rest_framework.authtoken
應用程序提供 Django 數據庫遷移。
您還須要爲您的用戶建立令牌。
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=...)
print token.key
複製代碼
對於客戶端進行身份驗證,令牌密鑰應包含在 Authorization
HTTP header 中。關鍵字應以字符串文字 「Token」 爲前綴,用空格分隔兩個字符串。例如:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
複製代碼
注意: 若是您想在 header 中使用不一樣的關鍵字(例如 Bearer
),只需子類化 TokenAuthentication
並設置 keyword
類變量。
若是成功經過身份驗證,TokenAuthentication
將提供如下憑據。
request.user
是一個 Django User
實例.request.auth
是一個 rest_framework.authtoken.models.Token
實例.未經身份驗證的響應被拒絕將致使 HTTP 401 Unauthorized
的響應和相應的 WWW-Authenticate header。例如:
WWW-Authenticate: Token
複製代碼
curl
命令行工具可能對測試令牌認證的 API 有用。例如:
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
複製代碼
注意: 若是您在生產中使用 TokenAuthentication
,則必須確保您的 API 只能經過 https
訪問。
若是您但願每一個用戶都擁有一個自動生成的令牌,則只需捕捉用戶的 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 啓動時將導入的其餘某個位置。
若是您已經建立了一些用戶,則能夠爲全部現有用戶生成令牌,例如:
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)
複製代碼
使用 TokenAuthentication
時,您可能但願爲客戶提供一種機制,以獲取給定用戶名和密碼的令牌。 REST framework 提供了一個內置的視圖來支持這種行爲。要使用它,請將 obtain_auth_token
視圖添加到您的 URLconf 中:
from rest_framework.authtoken import views
urlpatterns += [
url(r'^api-token-auth/', views.obtain_auth_token)
]
複製代碼
請注意,模式的 URL 部分能夠是任何你想使用的。
當使用表單數據或 JSON 將有效的 username
和 password
字段發佈到視圖時, obtain_auth_token
視圖將返回 JSON 響應:
{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
複製代碼
請注意,缺省的 obtain_auth_token
視圖顯式使用 JSON 請求和響應,而不是使用你設置的默認的渲染器和解析器類。
默認狀況下,沒有權限或限制應用於 obtain_auth_token
視圖。 若是您但願應用 throttling ,則須要重寫視圖類,並使用 throttle_classes
屬性包含它們。
若是你須要自定義 obtain_auth_token
視圖,你能夠經過繼承 ObtainAuthToken
視圖類來實現,並在你的 url conf 中使用它。
例如,您可能會返回超出 token
值的其餘用戶信息:
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
複製代碼
還有 urls.py
:
urlpatterns += [
url(r'^api-token-auth/', CustomAuthToken.as_view())
]
複製代碼
也能夠經過管理界面手動建立令牌。若是您使用的用戶羣很大,咱們建議您對 TokenAdmin
類進行修補以根據須要對其進行定製,更具體地說,將 user
字段聲明爲 raw_field
。
your_app/admin.py
:
from rest_framework.authtoken.admin import TokenAdmin
TokenAdmin.raw_id_fields = ('user',)
複製代碼
從版本 3.6.4 開始,可使用如下命令生成用戶令牌:
./manage.py drf_create_token <username>
複製代碼
此命令將返回給定用戶的 API 令牌,若是它不存在則建立它:
Generated token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b for user user1
複製代碼
若是您想從新生成令牌(例如,它已被泄漏),則能夠傳遞一個附加參數:
./manage.py drf_create_token -r <username>
複製代碼
此認證方案使用 Django 的默認 session 後端進行認證。Session 身份驗證適用於與您的網站在同一會話環境中運行的 AJAX 客戶端。
若是成功經過身份驗證,則 SessionAuthentication
會提供如下憑據。
request.user
是一個 Django User
實例.request.auth
是 None
.未經身份驗證的響應被拒絕將致使 HTTP 403 Forbidden
響應。
若是您在 SessionAuthentication 中使用 AJAX 風格的 API,則須要確保爲任何 「不安全」 的 HTTP 方法調用(例如 PUT
,PATCH
,POST
或 DELETE
請求)包含有效的 CSRF 令牌。
警告: 建立登陸頁面時應該始終使用 Django 的標準登陸視圖。這將確保您的登陸視圖獲得適當的保護。
REST framework 中的 CSRF 驗證與標準 Django 略有不一樣,由於須要同時支持基於 session 和非基於 session 的身份驗證。這意味着只有通過身份驗證的請求才須要 CSRF 令牌,而且能夠在沒有 CSRF 令牌的狀況下發送匿名請求。此行爲不適用於應始終應用 CSRF 驗證的登陸視圖。
這種身份驗證方案容許您將身份驗證委託給您的 Web 服務器,該服務器設置 REMOTE_USER
環境變量。
要使用它,你必須在你的 AUTHENTICATION_BACKENDS
設置中有 django.contrib.auth.backends.RemoteUserBackend
(或者一個子類)。默認狀況下,RemoteUserBackend
爲不存在的用戶名建立 User
對象。要改變這個和其餘行爲,請參考 Django 文檔。
若是成功經過身份驗證,RemoteUserAuthentication
將提供如下憑據:
request.user
是一個 Django User
實例.request.auth
是 None
.有關配置驗證方法的信息,請參閱您的 Web 服務器的文檔,例如:
要實現自定義身份驗證方案,請繼承 BaseAuthentication
並重寫 .authenticate(self, request)
方法。若是認證成功,該方法應返回 (user, auth)
的二元組,不然返回 None
。
在某些狀況下,您可能想要從 .authenticate()
方法引起 AuthenticationFailed
異常而不是返回 None
。
一般你應該採起的方法是:
None
。任何其餘正在使用的身份驗證方案仍將被檢查。AuthenticationFailed
異常。不管是否進行任何權限檢查,都將當即返回錯誤響應,而且再也不檢查任何其餘身份驗證方案。您也 能夠 重寫 .authenticate_header(self, request)
方法。若是實現,它應該返回一個字符串,該字符串將用做 HTTP 401 Unauthorized
響應中的 WWW-Authenticate header 的值。
若是未覆蓋 .authenticate_header()
方法,那麼當未經身份驗證的請求被拒絕訪問時,身份驗證方案將返回 HTTP 403 Forbidden
響應。
Note: 當請求對象的 .user
或 .auth
屬性調用您的自定義身份驗證器時,您可能會看到 AttributeError
做爲 WrappedAttributeError
被從新引起。這對於防止原始異常被外部屬性訪問所抑制是必要的。Python 不會識別 AttributeError
來自您的自定義身份驗證器,而是會假設請求對象沒有 .user
或 .auth
屬性。這些錯誤應該由您的驗證器修復或以其餘方式處理。
下面的示例將根據名爲 「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)
複製代碼