Authentication
認證是將一個傳入的請求和一組標識憑據相關聯的機制,比如請求過來的用戶,或者用戶登錄時攜帶的token。
然后權限策略就能使用這些憑據來決定是否允許這個請求。
REST框架提供了多種開箱即用的方案,也允許你實施自定義的方案。
認證總是在view的最開始運行,在權限檢查之前,在其他任何代碼被允許執行之前。
request.user屬性通常會被設為contrib.auth
包下的User類。
request.auth屬性被用做額外的認證信息。比如,作為一個請求簽名的認證token
記住一點,認證機制自己並沒有允許或不允許一個傳入的請求,它只是簡單的標識請求攜帶的憑據。
認證方案設定
全局
REST_FRAMEWORK = { ... 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', 'rest_framework.authentication.BasicAuthentication' ), } #默認是session+basic #對於前后端分離的項目,session認證一般刪掉,使用token,basic是必須放在這里的。 #在settings里設置默認認證類,然后會自上而下拿着請求來驗證,然后使用第一個成功認證的類返回用戶對象request.user (用戶信息)和request.auth(認證信息)。 #如果沒有類認證,request.user 會被設為 django.contrib.auth.models.AnonymousUser一個實例,request.auth 會設置為 None.
局部
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)
Unauthorized and Forbidden responses
當一個未被認證的請求被拒絕時,有兩種合適的error code
401返回必須包含一個WWW-Authenticate
header,指導客戶端需要如何認證。
403返回沒有包含WWW-Authenticate
header。
使用哪種返回,取決於認證方案。雖然有多種認證方案在使用,但可能只有一個方案用於決定返回的類型。
在確定響應類型時,將使用視圖上設置的第一個身份驗證類。
注意:當一個請求被成功認證時,但還是被拒絕執行請求,這種情況下,不論時哪種認證方案,總是使用403返回。
authentication.py源碼分析
class BaseAuthentication(object): """ All authentication classes should extend BaseAuthentication. """ def authenticate(self, request): """ Authenticate the request and return a two-tuple of (user, token). """ raise NotImplementedError(".authenticate() must be overridden.") def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ pass #所有認證類都是基於它擴展
BasicAuthentication
這個方案使用HTTP Basic Authentication,使用用戶的username和password進行簽名。一般只適合用於測試。
如果成功認證,它會提供以下憑據:
request.user
will be a DjangoUser
instance.request.auth
will beNone
.
未認證時返回401,帶一個WWW-Authenticate header。比如:
WWW-Authenticate: Basic realm="api"
TokenAuthentication
單單使用一個token-based HTTP認證方案。
首先需要在認證類設置中包含TokenAuthentication
此外在INSTALLED_APPS
設置中包含rest_framework.authtoken
INSTALLED_APPS = ( ... 'rest_framework.authtoken' )
然后要同步數據庫,因為rest_framework.authtoken會提供 Django database migrations.
[root@webmaster mofangsvr]# python3.7 manage.py showmigrations authtoken [ ] 0001_initial [ ] 0002_auto_20160226_1747 cmdb [X] 0001_initial #有個authtoken的app,有兩個migrations沒有同步 python3.7 manage.py migrate authtoken #同步數據
然后要創建url
from rest_framework.authtoken import views urlpatterns += [ path('api-token-auth/', views.obtain_auth_token) ] #在項目urls.py中加入就行
token測試
# curl -X POST -H "Content-Type:application/json" -d '{"username":"yueju_view","password":"123@abAB"}' http://192.168.10.10:8001/api-token-auth/ {"token":"e3205a50505096dacb3fbbadc7de79cd95b3af45"} #服務端返回了一個token #在authtoken_token表中產生了一條數據,和user_id關聯,但會發現沒有過期時間
class SvrprocessconfigTestViewSet(viewsets.ModelViewSet): serializer_class = SvrprocessconfigSerializer permission_classes = (IsAuthenticated,) #在一個類視圖中使用認證權限
curl -X GET http://192.168.10.10:8001/cmdb/svrprocess_Test/ {"detail":"身份認證信息未提供。"} #這時無法訪問,后台401認證錯誤
curl -X GET http://192.168.10.10:8001/cmdb/svrprocess_Test/ -H 'Authorization: Token e3205a50505096dacb3fbbadc7de79cd95b3af45' #帶上token,則成功返回數據
JWT認證
http://getblimp.github.io/django-rest-framework-jwt/
測試方式和token的一樣,唯一不一樣的就是token串變得長了幾倍,然后內容每次都是不一樣的。
去查源碼,可以發現是因為在串里加入了時間再進行加密。
過期時間
JWT_AUTH = { 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=20), } #jwt設置的默認過期時間是300s,可在項目settings中調整 #如果過期,則token不再生效。報以下錯誤 {"detail":"Signature has expired."}