django rest framework權限和認證


一.Authentication用戶認證配置

  1.四種驗證及官網描述: 

             BasicAuthentication

                                  此身份驗證方案使用HTTP基本身份驗證,根據用戶的用戶名和密碼進行簽名。基本身份驗證通常僅適用於測試。

                                  如果成功通過身份驗證,請BasicAuthentication提供以下憑據。

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

             .request.auth會的None

                                 拒絕許可的未經身份驗證的響應將導致HTTP 401 Unauthorized使用適當的WWW-Authenticate標頭進行響應。例如:

 WWW-Authenticate: Basic realm="api"

                                 注意:如果您BasicAuthentication在生產中使用,則必須確保您的API僅可用於https。您還應該確保您的API客戶端始終在登錄時重新請求用戶名和密碼,並且永遠不會將這些詳細信息存儲到持久存儲中。

       

             TokenAuthentication

                              此身份驗證方案使用基於令牌的簡單HTTP身份驗證方案。令牌認證適用於客戶端 - 服務器設置,例如本機桌面和移動客戶端。

        要使用該TokenAuthentication方案,您需要配置要包含的身份驗證類TokenAuthentication,並rest_framework.authtoken在您的INSTALLED_APPS設置中另外包含

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

        注意:確保manage.py migrate在更改設置后運行rest_framework.authtoken應用程序提供Django數據庫遷移。

           SessionAuthentication

        此身份驗證方案使用Django的默認會話后端進行身份驗證。會話身份驗證適用於與您的網站在同一會話上下文中運行的AJAX客戶端。

        如果成功通過身份驗證,請SessionAuthentication提供以下憑據。

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

        未經許可的未經身份驗證的響應將導致HTTP 403 Forbidden響應。

        如果您使用的是AJAX風格的API與SessionAuthentication,你需要確保你有一個有效的CSRF令牌任何“不安全”的HTTP方法調用,如PUTPATCHPOSTDELETE請求。有關更多詳細信息,請參閱Django CSRF文檔

        警告:創建登錄頁面時始終使用Django的標准登錄視圖。這將確保您的登錄視圖得到適當保護。

        REST框架中的CSRF驗證與標准Django的工作方式略有不同,因為需要同時支持基於會話和非會話的身份驗證。這意味着只有經過身份驗證的請求才需要CSRF令牌,並且可以在沒有CSRF令牌的情況下發送匿名請求。此行為不適用於登錄視圖,登錄視圖應始終應用CSRF驗證。

           RemoteUserAuthentication

                         此身份驗證方案允許您將身份驗證委派給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.Token驗證:

       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

 

二.動態設置permission,Authentication

  1.permission權限api(這里列舉幾個,更多可以參考官網http://www.django-rest-framework.org/api-guide/permissions/):

    IsAuthenticated:該IsAuthenticated許可類將拒絕允許任何未認證用戶,並允許許可,否則。如果您希望您的API僅供注冊用戶訪問,則此權限適用。

    IsAdminUser:所述IsAdminUser許可類將拒絕許可給任何用戶,除非user.is_staffTrue在這種情況下的許可將被允許。如果您希望只有可信管理員的子集可以訪問您的API,則此權限是合適的。

    IsAuthenticatedOrReadOnly:IsAuthenticatedOrReadOnly將允許經過身份驗證的用戶執行任何請求。只有在請求方法是“安全”方法之一時,才允許對未經授權的用戶提出請求; GETHEADOPTIONS。如果您希望API允許匿名用戶具有讀取權限,並且僅允許對經過身份驗證的用戶具有寫入權限,則此權限是合適的。

  2.自定義權限:

    例子:

    以下是根據黑名單檢查傳入請求的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)
......

   3.動態判斷:

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()

 

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM