1. 程式人生 > >【DRF框架】認證元件

【DRF框架】認證元件

DRF框架的認證元件

核心程式碼:       self.perform_authentication(request) 

框架自帶模組:    from rest_framework import authentication

 

認證元件的返回值:request.user

自定義的認證元件的鉤子方法authenticator.authenticate(self) ;返回值是元組(user,auth)

 

from rest_framework import authentication

from rest_framework import authentication


class BaseAuthentication(object):
    def authenticate(self, request):
        # 必須重寫該方法,返回元組(user,auth)
        return (user_obj,token)


class BasicAuthentication(BaseAuthentication):


class SessionAuthentication(BaseAuthentication):


class TokenAuthentication(BaseAuthentication):
    

class RemoteUserAuthentication(BaseAuthentication):


基於BaseAuthentication類的認證
# myauth.py


from rest_framework import authentication
from AuthDemo.models import UserTable
from rest_framework.exceptions import AuthenticationFailed      # 用於丟擲異常


# 基於BaseAuthentication類的認證
class AuthoDemo(authentication.BaseAuthentication):
    
'''驗證GET請求是否攜帶Token''' def authenticate(self, request): # 通過/user/test/?token="xxx" 獲取token token = request.query_params.get("token","") # 如果token不存在 if not token: # 丟擲異常 raise AuthenticationFailed("token不存在") # token存在,驗證token user_obj = UserTable.objects.filter(token=token).first() if user_obj: # 驗證通過,必須返回元組,(user,token) return (user_obj,token) # 認證不通過丟擲異常 raise AuthenticationFailed("token錯誤")
# views.py

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import UserTable
import uuid
from utils.myauth import AuthoDemo
from rest_framework import authentication

# Create your views here.

# 註冊檢視
class RegisterView(APIView):
    def post(self,request):
        # 獲取提交的使用者名稱和密碼
        username = request.data.get('username')
        password = request.data.get('password')

        # 建立物件
        UserTable.objects.create(username=username,password=password)

        # 返回結果
        return Response("註冊成功!")

# 登陸檢視
class LoginView(APIView):
    def post(self,request):
        # 獲取提交的使用者名稱和密碼
        username = request.data.get('username')
        password = request.data.get('password')
        # 驗證使用者名稱密碼是否正確
        user_obj = UserTable.objects.filter(username=username,password=password).first()
        if user_obj:
            # 驗證通過,寫入Token並儲存
            token = uuid.uuid4()
            user_obj.token = token           # 為物件的token欄位寫入隨機字串
            user_obj.save()
            # 返回token
            return Response(token)
        else:
            return Response("使用者名稱密碼不正確")


# 認證的測試檢視
class TestView(APIView):
    authentication_classes = [AuthoDemo,]
    def get(self,request):
        print(request.user)             # 獲取使用者物件
        print(request.auth)             # 獲取token
        print(request.user.username)    # 獲取使用者物件的名字
        return Response("認證測試介面")

 

 

原始碼流程

# 1、封裝request物件
def dispatch(self, request, *args, **kwargs):
    request = self.initialize_request(request, *args, **kwargs)

# 1.1
def initialize_request(self, request, *args, **kwargs):
    parser_context = self.get_parser_context(request)
    return Request(
        request,
        parsers=self.get_parsers(),
        # 返回認證類的例項化物件列表:[auth() for auth in self.authentication_classes]
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )


# 1.2
class APIView(View):
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES


from rest_framework import authentication  # 檢視自帶的認證類


class ApiView(View):
    # 2、認證元件
    self.perform_authentication(request)
    # 許可權元件
    self.check_permissions(request)
    # 節流元件
    self.check_throttles(request)
  
    
# 2.1、開始認證
def perform_authentication(self, request):
    request.user


# 2.2、呼叫Request.user
class Request(object):
    def __init__(self, request, authenticators=None):
        self.authenticators = authenticators or ()

    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                # 2.3、
                self._authenticate()  
        return self._user   


# 2.3、讀取認證物件列表
def _authenticate(self):
    for authenticator in self.authenticators:
        try:
            # 對每個進行驗證,異常則全部終止,若返回None,則繼續迴圈
            user_auth_tuple = authenticator.authenticate(self)
            
        except exceptions.APIException:
            self._not_authenticated()
            raise

        if user_auth_tuple is not None:
            # 給request賦值user
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            # 通過直接退出迴圈
            return
    
    # 全都沒有通過則設定匿名使用者
    self._not_authenticated()


# 認證類例項
class BasicAuthentication(BaseAuthentication):
    def authenticate(self, request):
        """
        Returns a `User` if a correct username and password have been supplied
        using HTTP Basic authentication.  Otherwise returns `None`.
        """
        pass
        return self.authenticate_credentials(userid, password, request)
        
     def authenticate_credentials(self, userid, password, request=None):
        """
        Authenticate the userid and password against username and password
        with optional request for context.
        """
        user = authenticate(request=request, **credentials)

        if user is None:
            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

        if not user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
            
        return (user, None)