此身份驗證方案使用HTTP基自己份驗證,根據用戶的用戶名和密碼進行簽名。基自己份驗證一般僅適用於測試。html
若是成功經過身份驗證,請BasicAuthentication
提供如下憑據。nginx
.request.user
將是一個Django User
實例。 ajax
.request.auth
會的None
。數據庫
拒絕許可的未經身份驗證的響應將致使HTTP 401 Unauthorized
使用適當的WWW-Authenticate標頭進行響應。例如:apache
WWW-Authenticate: Basic realm="api"
注意:若是您BasicAuthentication
在生產中使用,則必須確保您的API僅可用於https
。您還應該確保您的API客戶端始終在登陸時從新請求用戶名和密碼,而且永遠不會將這些詳細信息存儲到持久存儲中。django
此身份驗證方案使用基於令牌的簡單HTTP身份驗證方案。令牌認證適用於客戶端 - 服務器設置,例如本機桌面和移動客戶端。後端
要使用該TokenAuthentication
方案,您須要配置要包含的身份驗證類TokenAuthentication
,並rest_framework.authtoken
在您的INSTALLED_APPS
設置中另外包含:api
INSTALLED_APPS = ( ... 'rest_framework.authtoken' )
注意:確保manage.py migrate
在更改設置後運行。該rest_framework.authtoken
應用程序提供Django數據庫遷移。安全
此身份驗證方案使用Django的默認會話後端進行身份驗證。會話身份驗證適用於與您的網站在同一會話上下文中運行的AJAX客戶端。服務器
若是成功經過身份驗證,請SessionAuthentication
提供如下憑據。
request.user
將是一個Django User
實例。request.auth
會的None
。 未經許可的未經身份驗證的響應將致使HTTP 403 Forbidden
響應。
若是您使用的是AJAX風格的API與SessionAuthentication,你須要確保你有一個有效的CSRF令牌任何「不安全」的HTTP方法調用,如PUT
,PATCH
,POST
或DELETE
請求。有關更多詳細信息,請參閱Django CSRF文檔。
警告:建立登陸頁面時始終使用Django的標準登陸視圖。這將確保您的登陸視圖獲得適當保護。
REST框架中的CSRF驗證與標準Django的工做方式略有不一樣,由於須要同時支持基於會話和非會話的身份驗證。這意味着只有通過身份驗證的請求才須要CSRF令牌,而且能夠在沒有CSRF令牌的狀況下發送匿名請求。此行爲不適用於登陸視圖,登陸視圖應始終應用CSRF驗證。
此身份驗證方案容許您將身份驗證委派給Web服務器,該服務器設置REMOTE_USER
環境變量。
要使用它,您必須django.contrib.auth.backends.RemoteUserBackend
在您的AUTHENTICATION_BACKENDS
設置中擁有(或子類) 。默認狀況下,爲尚不存在的用戶名RemoteUserBackend
建立User
對象。要更改此行爲和其餘行爲,請參閱 Django文檔。
若是成功經過身份驗證,請RemoteUserAuthentication
提供如下憑據:
request.user
將是一個Django User
實例。request.auth
會的None
。有關配置身份驗證方法的信息,請參閱Web服務器的文檔,例如:
要實現自定義身份驗證方案,請子類化BaseAuthentication
並覆蓋該.authenticate(self, request)
方法。(user, auth)
若是身份驗證成功,則該方法應返回兩元組,None
不然返回。
在某些狀況下None
,您可能但願AuthenticationFailed
從該.authenticate()
方法引起異常,而不是返回。
一般,您應採起的方法是:
None
。還將檢查還在使用的任何其餘身份驗證方案。AuthenticationFailed
異常。不管是否進行任何權限檢查,都將當即返回錯誤響應,而且不會檢查任何其餘身份驗證方案。 您也能夠覆蓋該.authenticate_header(self, request)
方法。若是實現,它應返回一個字符串,該字符串將用做響應WWW-Authenticate
中標頭的值HTTP 401 Unauthorized
。
若是.authenticate_header()
未覆蓋該方法,則在HTTP 403 Forbidden
拒絕未經身份驗證的請求訪問時,身份驗證方案將返回響應。
注意:當請求對象.user
或.auth
屬性調用您的自定義身份驗證器時,您可能會看到AttributeError
從新提高爲WrappedAttributeError
。這是防止外部屬性訪問抑制原始異常所必需的。Python不會識別AttributeError
來自自定義身份驗證器的orginates,而是假設請求對象沒有.user
或.auth
屬性。這些錯誤應由您的驗證者修復或以其餘方式處理。
2.1setting.py中的install-app添加app:
#Token驗證,會生成表
'rest_framework.authtoken',
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', #添加Token驗證,若是Token過時,不須要登陸的界面也不能訪問,最好配置在具體的頁面 ),
生成token表,用戶登陸後會建立對應的key
2.2使用時TokenAuthentication
,您可能但願爲客戶端提供一種機制,以獲取給定用戶名和密碼的令牌。REST框架提供了一個內置視圖來提供此行爲。要使用它,請將obtain_auth_token
視圖添加到URLconf:
from rest_framework.authtoken import views #配置url urlpatterns += [ url(r'^api-token-auth/', views.obtain_auth_token) ]
2.3Django請求到響應全過程:http://www.projectsedu.com/
2.4TokenAuthentication源碼:
def get_authorization_header(request): """ Return request's 'Authorization:' header, as a bytestring. Hide some test client ickyness where the header can be unicode. """ auth = request.META.get('HTTP_AUTHORIZATION', b'') if isinstance(auth, text_type): # Work around django test client oddness auth = auth.encode(HTTP_HEADER_ENCODING) return auth
經過該函數獲取Token並返回
def authenticate(self, request): auth = get_authorization_header(request).split() if not auth or auth[0].lower() != self.keyword.lower().encode(): return None if len(auth) == 1: msg = _('Invalid token header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: msg = _('Invalid token header. Token string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) try: token = auth[1].decode() except UnicodeError: msg = _('Invalid token header. Token string should not contain invalid characters.') raise exceptions.AuthenticationFailed(msg) return self.authenticate_credentials(token)
而後經過authenticate判斷token是否合法
def authenticate_credentials(self, key): model = self.get_model() try: token = model.objects.select_related('user').get(key=key) except model.DoesNotExist: raise exceptions.AuthenticationFailed(_('Invalid token.')) if not token.user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (token.user, token)
到token表中查找是否對應token
IsAuthenticated:該IsAuthenticated
許可類將拒絕容許任何未認證用戶,並容許許可,不然。若是您但願您的API僅供註冊用戶訪問,則此權限適用。
IsAdminUser:所述IsAdminUser
許可類將拒絕許可給任何用戶,除非user.is_staff
是True
在這種狀況下的許可將被容許。若是您但願只有可信管理員的子集能夠訪問您的API,則此權限是合適的。
IsAuthenticatedOrReadOnly:這IsAuthenticatedOrReadOnly
將容許通過身份驗證的用戶執行任何請求。只有在請求方法是「安全」方法之一時,才容許對未經受權的用戶提出請求; GET
,HEAD
或OPTIONS
。若是您但願API容許匿名用戶具備讀取權限,而且僅容許對通過身份驗證的用戶具備寫入權限,則此權限是合適的。
如下是根據黑名單檢查傳入請求的IP地址的權限類的示例,若是IP已被列入黑名單,則拒絕該請求。
from rest_framework import permissions class BlacklistPermission(permissions.BasePermission): """ Global permission check for blacklisted IPs. """ def has_permission(self, request, view): ip_addr = request.META['REMOTE_ADDR'] blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists() return not blacklisted
除了針對全部傳入請求運行的全局權限以外,您還能夠建立對象級權限,這些權限僅針對影響特定對象實例的操做運行。例如:
class IsOwnerOrReadOnly(permissions.BasePermission): """ Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """ 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 # Instance must have an attribute named `owner`. return obj.owner == request.user
自定義驗證(能夠新建一個文件):
from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): 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 # Instance must have an attribute named `owner`. return obj.user == request.user
views中使用驗證:
...... from utils.permissions import IsOwnerOrReadOnly # Create your views here. class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): ''' list: 獲取用戶收藏列表 retrieve: 判斷某個商品是否收藏 create: 收藏商品 ''' # queryset = UserFav.objects.all() permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) ......
from rest_framework import permissions from rest_framework import authentication from rest_framework_jwt.authentication import JSONWebTokenAuthentication ...... class UserViewset(mixins.CreateModelMixin,mixins.UpdateModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet): ''' 用戶 ''' serializer_class = UserRegSerializer queryset = User.objects.all() authentication_classes = (JSONWebTokenAuthentication,authentication.SessionAuthentication) #更新,添加用戶信息放在一塊兒,是否登陸應該動態,註冊不用登陸IsAuthenticated,該方法不行 # permission_classes = (permissions.IsAuthenticated) def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user=self.perform_create(serializer) re_dict=serializer.data payload=jwt_payload_handler(user) re_dict['token']=jwt_encode_handler(payload) re_dict['name']=user.name if user.name else user.username headers = self.get_success_headers(serializer.data) return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) def get_serializer_class(self): ''' 重載GenericAPIView中的get_serializer_class函數,調用不一樣的序列化類,若是是create, 就調用UserRegSerializer序列化,不然UserDetailSerializer序列化 :return: ''' if self.action == 'retrieve': return UserDetailSerializer elif self.action == 'create': return UserRegSerializer return UserDetailSerializer def get_permissions(self): ''' 重載APIview中的get_perimissions函數,若是是新增用戶則不用登陸,不然必須登陸 :return: ''' if self.action == 'retrieve': return [permissions.IsAuthenticated()] elif self.action == 'create': return [] return [] def get_object(self): ''' 返回當前用戶 :return: ''' return self.request.user def perform_create(self, serializer): return serializer.save()