drf 三大認證詳解


drf 三大認證:

認證:

# 全局配置:
	-在全局(認證組件只能決定request.user,不是斷定權限的地方,所以一般配置全局)
    
REST_FRAMEWORK = {
    # 認證組件
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
    ],
}



# 局部禁用(login 模塊):

authentication_classes = ''
permission_classes = ''

from rest_framework_jwt.authentication import JSONWebTokenAuthentication
# authentication_classes = [JSONWebTokenAuthentication]


#自定義認證類:
    1) 如果使用session認證,drf默認提供了SessionAuthentication
    2) 如果使用drf-jwt認證框架,drf-jwt框架提供了JSONWebTokenAuthentication
    3) 如果是自定義簽發與校驗token,才需要將校驗token的算法封裝到自定義的認證類中
    
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        """
        1) 從請求頭中拿到前台提交的token(一般從HTTP_AUTHORIZATION中拿,也可以與前台約定)
              -- 如果設置了反爬等措施,校驗一下反爬(頭 token)
        2)沒有token,返回None,代表游客
        3)有token,進入校驗
              -- 不通過:拋AuthenticationFailed異常,代表非法用戶
              -- 通過:返回 (user, token),代表合法用戶
        """
        pass



#認證規則:
	認證組件:校驗用戶 - 游客、合法用戶、非法用戶
    游客:代表校驗通過,直接進入下一步校驗(權限校驗)
    合法用戶:代表校驗通過,將用戶存儲在request.user中,再進入下一步校驗(權限校驗)
    非法用戶:代表校驗失敗,拋出異常,返回403權限異常結果
    只要通過認證不管是游客還是登錄用戶,request.user都有值

權限:

#drf 自帶權限組件:
	IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly

#自定義:
自定義權限類:
1) drf默認提供了一些權限類
    AllowAny:游客和登錄用戶有全權限
    IsAuthenticated:只有登錄用戶有全權限
    IsAdminUser:只有后台用戶(admin用戶)有全權限
    IsAuthenticatedOrReadOnly:游客有讀權限,登錄用戶有全權限
2)如果有特殊需要,需要自定義權限類
    如:只有superuser有權限、只有vip用戶有權限、只有某ip網段用戶有權限、只有某個視圖及其子類有權限
    根據需求,request和view的輔助,制定權限規則判斷條件

默認權限:
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.AllowAny',
],


#permissions.py (vip 分組權限管理)
from rest_framework.permissions import BasePermission
class MyAPIView(APIView):
	permission_classes = [permissions.VIPUserPermission]
    
class VIPUserPermission(BasePermission):  # 只要vip分組用戶有權限
    def has_permission(self, request, view):
        for group in request.user.groups.all():
            if group.name.lower() == 'vip':
                return True  # 有權限
        return False  # 無權限


認證與權限組件綁定使用:

    1)每一個視圖類都要進行認證校驗,且認證規則一致,所以全局配置認證類即可
    2)每一個視圖類都要進行權限校驗,默認配置的是不限制(AllowAny),但實際開發中,視圖類的訪問權限不盡相同,所以要在具體
        的視圖類,配置具體的權限規則

from rest_framework.viewsets import ViewSet
class UserViewSet(ViewSet):
    # 權限:只有VIP用戶可以查看個人詳細詳細
    permission_classes = [permissions.VIPUserPermission]

    def retrieve(self, request, *args, **kwargs):
        return APIResponse(results={
            'username': request.user.username,
            'email': request.user.email,
            'mobile': request.user.mobile,
            'data_joined': request.user.date_joined,
        })

頻率:

from rest_framework.throttling import SimpleRateThrottle
"""
自定義頻率類
1) drf默認提供了一些頻率類 
    AnonRateThrottle:只對游客進行頻率限制
    UserRateThrottle:對所有用戶進行頻率限制
2)如果有特殊需要,需要自定義頻率類
    如:對ip進行限次、對電話進行限制、對視圖某些信息進行限次
"""
class MobileRateThrottle(SimpleRateThrottle):
    """
    1)設置scope字符串類屬性,同時在settings中進行drf配置DEFAULT_THROTTLE_RATES
        eg: DEFAULT_THROTTLE_RATES = {'mobile': '1/min'}
    2)重寫get_catch_key方法:
        返回與限制條件有關的字符串,表示限制
        返回None,表示不限制
    """
    scope = 'mobile'
    def get_cache_key(self, request, view):
        if not request.user.is_authenticated or not request.user.mobile:
            return None  # 匿名用戶 或 沒有電話號的用戶 都不限制

        # 只要有電話號的用戶踩進行限制
        return self.cache_format % {
            'scope': self.scope,
            'ident': request.user.mobile
        }

多方式登錄:

from rest_framework.views import APIView
class LoginAPIView(APIView):
    """ 重點
    1)token只能由 登錄接口 簽發
    2)登錄接口也是APIView的子類,使用一定會進行 認證、權限 組件的校驗
    結論:不管系統默認、或是全局settings配置的是何認證與權限組件,登錄接口不用參與任何認證與權限的校驗
    所以,登錄接口一定要進行 認證與權限 的局部禁用
    """
    authentication_classes = []
    pagination_class = []

    def post(self, request, *args, **kwargs):
        serializer = serializers.LoginModelSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 內部在全局鈎子中完成token的簽發
        return APIResponse(results={
            'username': serializer.content.get('user').username,
            'token': serializer.content.get('token')
        })

#serializer.py

from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
import re
class LoginModelSerializer(serializers.ModelSerializer):
    # post請求,序列化默認當做create動作進行校驗,需要校驗數據庫,create動作username會拋用戶已存在異常
    # 拋用戶已存在異常是多余的,所以自定義系統校驗規則即可
    username = serializers.CharField(min_length=3, max_length=16)
    password = serializers.CharField(min_length=3, max_length=16)
    class Meta:
        model = models.User
        fields = ('username', 'password')

    # 用全局鈎子,完成token的簽發
    def validate(self, attrs):
        # 1)通過 username 和 password 完成多方式登錄校驗,得到user對象
        user = self._validate_user(attrs)
        # 2)user對象包裝payload載荷
        payload = jwt_payload_handler(user)
        # 3)payload載荷簽發token
        token = jwt_encode_handler(payload)
        # 4)將user與token存儲到serializer對象中,方便在視圖類中使用
        self.content = {
            'user': user,
            'token': token
        }
        return attrs

    def _validate_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')

        if re.match(r'.*@.*', username):  # 郵箱
            user = models.User.objects.filter(email=username).first()  # type: models.User
        elif re.match(r'^1[3-9][0-9]{9}$', username):  # 電話
            user = models.User.objects.filter(mobile=username).first()
        else:  # 用戶名
            user = models.User.objects.filter(username=username).first()

        if not user or not user.check_password(password):
            raise serializers.ValidationError({'message': '用戶信息異常'})

        return user

自定義簽發token :

    1)將請求數據交給序列化類,執行序列化校驗
    2)在序列化全局校驗鈎子中,完成user的認證與token的簽發,保存在序列化對象的content中
    3)在視圖類中從序列化對象的content中拿user與token相關信息返回
    注:多方式登錄體現在 請求的賬號類型可能是用戶名、郵箱或手機等,采用不同字段校驗數據庫即可


免責聲明!

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



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