三大認證之認證組件和權限組件

一. 源碼分析

  

1. APIView的dispath(self, request, *args, **kwargs)
2. dispath方法內self.initial(request, *args, **kwargs)
    # 認證組件: 校驗用戶  -  遊客, 合法用戶, 非法用戶
    # 遊客: 表明着校驗已經經過,直接進入下一步校驗(權限校驗)
    # 合法用戶: 表明校驗經過,將數據保存在request.user中,在進行下一步校驗(權限校驗)
    # 非法用戶: 表明校驗失敗,拋出異常,返回403權限異常結果
    self.perform_authentication(request)

    # 權限組件: 校驗用戶權限 - 必須登陸,全部用戶,登陸讀寫遊客只讀,自定義用戶角色
    # 認證經過: 能夠進入下一步校驗(頻率認證)
    # 認證失敗: 拋出異常,返回403權限異常結果
    self.check_permissions(request)

    # 頻率組件: 限制試圖接口訪問的頻率次數 - 限制條件(IP, ID, 惟一鍵), 頻率週期時間(s, m, h), 頻率的次數
    # 沒有達到限次, 正常訪問接口
    # 達到限次, 限制時間內不能訪問,限制時間到達後,能夠從新訪問
    self.check_throttles(request)




3. 認證組件
    request類的  方法屬性 user 的get方法==>self._authenticate()完成認證


    認證細則:
    # 作認證
    def _authenticate(self):
        # 遍歷到一個個認證器, 進行認證
        # self.authenticators配置的一堆認證類產生的認證類對象組成的list
        for authenticator in self.authenticators:
            try:
                # 認證器調用認證方法authenticate(認證類對象self, request請求對象)
                # 返回值: 登陸的用戶與認證的信息組成的 tuple
                # 該方法被try包裹, 表明該方法會拋異常,拋異常就表明認證失敗
                user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
                self._not_authenticated()
                raise
        # 返回值處理
        if user_auth_tuple is not None:
            self._authenticator = authenticator
            # 若是有返回值, 就將登陸用戶與登陸認證分別保存在request.user, request.auth
            self.user, self.auth = user_auth_tuple
            return
        self._not_authenticated()



4. 權限組件
    self.check_permissions(request)
        認證細則:
    def check_permissions(self, request):
        # 遍歷權限對象列表獲得一個個權限對象(權限器), 進行權限認證
        for permission in self.get_permissions():
            # 權限類必定有一個has_permission權限方法, 歷來作權限認證的
            # 參數: 權限對象self, 請求對象request, 視圖類對象
            # 返回值: 有權限返回True, 無權限返回False
            if not permission.has_permission(request, self)
                self.permission_denied(
                request, message = getattr(permission, 'message', None)

 

二. 自定義建立類

1. 建立繼承BaseAuthentication的認證類
2. 實現authenticate方法
3. 實現體根據認證規則 肯定遊客, 非法用戶, 合法用戶
4. 進行全局或者局部配置


認證規則: 
1. 沒有認證信息就返回None(遊客)
2. 有認證信息認證失敗拋異常(非法用戶)
3. 有認證信息認證成功返回用戶與認證信息元組(合法用戶)

  utils/authentications.pydjango

自定義認證類

    
    1. 繼承BaseAuthentication類
    2. 從新authenticate(self, request)方法, 自定義認證規則
    3. 認證規則基於的條件:
        沒有認證信息就返回None(遊客)
        有認證信息認證失敗拋異常(非法用戶)
        有認證信息認證成功返回用戶與認證信息的元組(合法用戶)
    4. 徹底視圖類的全局(settings文件中)或是局部(確切的視圖類)配置

from  rest_framework.authentication import BaseAuthentication
from  rest_framework.exceptions import AuthenticationFailed
from . import models

class MyAuthentication(BaseAuthentication):
    # 從前臺請求頭那認證信息auth(獲取認證的字段要與前臺約定)
    # 沒有auth是遊客,返回None
    # 有auth進行校驗: 失敗是非法用戶,拋出異常, 成功是合法用戶,返回(用戶, 認證信息)


def authenticate(self, request):
    # 前臺在請求頭攜帶認證信息,默認規範用Authorization字段攜帶認證信息
    # 後臺固定在請求對象的META字段中, HTTP_AUTHORIZATION獲取
    auth = request.META.get('HTTP_AUTHORIZATION', None)
    # 處理遊客
    if auth is None:
        return None
    # 設置一下認證字段小規則(兩段式): "auth  認證字符串"
    auth_list = auth.split()
    # 檢驗合法用戶仍是非法用戶
     if not (len(auth_list) == 2 and auth_list[0].lower() == 'auth'):
            raise AuthenticationFailed("認證信息有誤, 非法用戶")
    # 合法用戶還須要從auth_list[1]中解析出來
    # 假設一種狀況,信息爲abc.123.xyz, 就能夠解析出admin用戶
    if auth_list[1] != 'abc.123.xyz'  # 校驗失敗
        raise AuthenticationFailed("用戶校驗失敗,非法用戶")
    user = models.User.objects.filter(username='admin').first()
    if not user:
        raise AuthenticationFailed("用戶數據有誤, 非法用戶")
    return (user, None)

 

三. 系統權限類api

1. AllowAny: 認證規則所有返還True: return True
        遊客與登陸用戶都有全部權限
2. IsAuthenticated:
        認證規則必須有登陸的合法用戶: return bool(request.user and
request.user.is_authenticated)
    遊客沒有任何權限
3. IsAdminUser:
        認證規則必須是後臺管理用戶: return bool(request.user and request.user.is_staff)
        遊客沒有任何權限,登陸用戶纔有權限
4. IsAuthenticatedOrReadOnly
        認證規則必須是隻讀請求或者是合法用戶:
        return bool(
                 request.method in SAFE_METHODS or
                 request.user and 
                 request.user.is_authenticated
)    
           遊客只讀,合法用戶無限制

# api/views.py
from rest_framework.permissions import IsAuthenticated

class TesttAuthenticatedAPIView(APIView):
  permission_classes = [IsAauthenticated]
  def get(self, request, *args, **kwargs )
    return APIResponse(0, 'test 登陸才能訪問接口')


# 默認全局配置的權限類是AllowAny
# settings.py
REST_FRAMEWORK = {
# 權限類配置
   'DEFAULT_PERMISSION_CLASSES':[
      'rest_framework.permissions.AllowAny',
],
}

  

自定義權限類

1. 建立繼承BasePermission的權限類
2. 實現has_permission方法
3. 實現體根據權限規則,肯定有無權限
4. 進項全體或者局部配置


認證規則:
 1. 知足設置的用戶條件, 表明有權限, 返回True
2. 不知足設置的用戶條件, 表明有權限, 返回False
# utils/permissions.py

from rest_framework.permissions import BasePermission
from django.contrib.auth.models import Group

class MyPermission(BasePermission):
    def has_permission(self, request, view)
        # 只讀接口判斷
        r1 = request.method in ('GET', 'HEAD', 'OPTIONS')
        # group爲有權限的分組
        group = Group.objects.filter(name='管理員').first()
        # groups爲當前用戶所屬的全部分組
        groups = request.user.groups.all()
        r2 = group and groups
        r3 = group in groups
        # 讀接口你們都有權限,寫接口必須爲指定分組下的登陸用戶
        return r1 or (r2 and r3)


# 遊客只讀, 登陸用戶只讀, 只有登陸用戶屬於管理員分組,才能夠增刪改查
from utils.permissions import MyPermission
class TestAdminOrReadOnlyAPIView(APIView):
    permission_classes = [MyPermission]
    # 全部用戶都能訪問
    def get(self, request, *args, **kwargs):
        return APIResponse(0, '自定義讀')
    # 必須是自定義"管理員分組"下的用戶
     def post(self, request, *args, **kwargs):
    
        return APIResponse(0, '本身寫')
相關文章
相關標籤/搜索