Drf之局部認證和全局認證(六)

登錄的token操作

# app.models.py:表結構
class User(models.Model):
    user = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)

class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to='User')
    
    
# app.objson.py:序列化模塊
from rest_framework import serializers
from app import models
class UserJson(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = '__all__'

        
# app.views.py      
from rest_framework.views import APIView
from rest_framework.response import Response
from app import common, models, objson
class Login(APIView):
    def post(self, request):
        # 用前臺提交的數據完成數據庫查詢校驗
        data_dic = request.data
        user = models.User.objects.filter(**data_dic).first()
        
        if user:
            # 登錄成功操作token
            token = common.get_token()
            # token的數據庫操作,第一次產生token是新建,再次就是更新
            models.UserToken.objects.update_or_create(user=user, defaults={"token": token})
            user_data = objson.UserJson(user).data
            return Response({
                "status": 0,
                "msg": 'login success',
                "token": token,  # 將token返回給前臺
                "results": user_data
            })
        return Response({
            "status": 1,
            "msg": 'login failed'
        })

認證方法的實現

# 源碼分析
# as_view() => APIView.dispatch => self.initial(request, *args, **kwargs) => 封裝後的drf的request => request.user => self._authenticate() => authenticate(self, request) 的源碼根據地

# app.views.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class LoginAuthenticate(BaseAuthentication):
    def authenticate(self, request):
        # 登錄邏輯:如果用戶登錄了,登錄操作產生了token,且前後臺同步了
        # 登錄判斷:再次發生的請求,沒有token代表沒登錄,錯誤token,代表無效的登錄,token正確纔是正常的登錄用戶
        # 如何將token取出, 規定token用請求頭傳遞
        token = request.META.get('HTTP_TOKEN')
        result = models.UserToken.objects.filter(token=token).first()
        if result:
            # 認證通過,可以返回None (有多個認證時),可以返回兩個值:user,auth,源碼中可以看到必須返回user,後面的值可以返回token(單獨token認證)、auth(多認證)或者None(認證不通過)
            return result.user, token
        else:
            # 驗證失敗,拋出APIException或其子類對象
            raise AuthenticationFailed("認證失敗")
            
class Books(APIView):
    authentication_classes = [LoginAuthenticate]
    # 視圖函數處理的邏輯
    def get(self, request):
        # 通過認證後,用request.user拿到當前登錄的用戶,用request.auth拿到認證值(該值通常自定義)
        print(request.user)
        return Response({
            "status": 0,
            "msg": 'ok',
            "results": []
        })

局部認證

# app.auth.py 完成校驗的所有邏輯
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app import models
class LoginAuthenticate(BaseAuthentication):
    def authenticate(self, request):
        token = request.META.get('HTTP_TOKEN')
        result = models.UserToken.objects.filter(token=token).first()
        if result:
            return result.user, token
        else:
            raise AuthenticationFailed("認證失敗")
            
# 局部認證: 在需要認證的類上方標註認證類:authentication_classes = [auth1, ... authn]
from app import auth
class Books(APIView):
    authentication_classes = [auth.LoginAuthenticate]
    def get(self, request):
        print(request.user)
        return Response({
            "status": 0,
            "msg": 'ok',
            "results": []
        })

# 案例:訪問當前登錄用戶信息 - 個人主頁
class Home(APIView):
	# 添加登錄認證即可
    authentication_classes = [auth.LoginAuthenticate]
    def get(self, request):
        return Response({
            "status": 0,
            "msg": 'ok',
            "results": objson.UserJson(request.user).data
        })

全局認證

# 1.在settings.py中配置
# 全局認證
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'app.auth.LoginAuthenticate'
    ),
}

# 2.所有的CBV類都不需要添加類屬性:authentication_classes

# 局部禁用
# 3.在不需要認證的CBV類中添加類屬性:authentication_classes = []



註銷:在全局認證情況下

class Logout(APIView):
    # 在全局認證情況下,如果能走get方法,代表已經通過登錄認證(登錄狀態),就可以註銷
    def get(self, request):
        models.UserToken.objects.update_or_create(user=request.user, defaults={'token': common.get_token()})
        return Response({
            "status": 0,
            "msg": 'logout success',
        })

補充:前臺操作cookie

<body>
<button class="login">登錄請求</button>
<button class="token">獲取token</button>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script>
    $('.login').click(function () {
        token = '88888';
        $.cookie('qt', '前臺操作cookie');
        $.cookie('token', token);
    });

    $('.token').click(function () {
        alert($.cookie('token'))
    })
</script>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章