drf 认证流程解析

认证

用于必须登录后才能访问否个视图。

简单使用:

url.py

from django.conf.urls import url,include
from django.contrib import admin
from . import views
urlpatterns = [
    url(r'^login/$', views.LoginView.as_view()),
    url(r'^order/$', views.OrderView.as_view()),
    url(r'^user/$', views.UserView.as_view()),
]

views.py

import uuid
from django.shortcuts import render
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIView
from rest_framework.response import Response

from . import models

class LoginView(APIView):

    def post(self,request,*args,**kwargs):
        user_object = models.UserInfo.objects.filter(**request.data).first()
        if not user_object:
            return Response('登录失败')
        random_string = str(uuid.uuid4())	# 产生随机字符串
        user_object.token = random_string	#  保存在数据库
        user_object.save()
        return Response(random_string)

    
class MyAuthentication:
    def authenticate(self, request):
        # 重写这个方法
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        token = request.query_params.get('token')
        # 获取请求携带的token,然后获取用户对象
        user_object = models.UserInfo.objects.filter(token=token).first()
        if user_object:
            return (user_object,token)
        return (None,None)

    
class OrderView(APIView):
    authentication_classes = [MyAuthentication, ]
    # 需要登录认证的视图,设置类列表
    def get(self,request,*args,**kwargs):
        print(request.user)		# 获取用户对象
        print(request.auth)		# 获取token
        return Response('order')

class UserView(APIView):
    authentication_classes = [MyAuthentication,]
    def get(self,request,*args,**kwargs):
        print(request.user)
        print(request.auth)
        return Response('user')

源码:

class APIView(View):
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    
	def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        # ###################### 第一步 ###########################
        """
        request,是django的request,它的内部有:request.GET/request.POST/request.method
        args,kwargs是在路由中匹配到的参数,如:
            url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
            http://www.xxx.com/order/1/v2/
        """
        self.args = args
        self.kwargs = kwargs


        """
        request = 生成了一个新的request对象,此对象的内部封装了一些值。
        request = Request(request)
            - 内部封装了 _request = 老的request
            - 内部封装了 authenticators = [MyAuthentication(), ] 对象类列表
        """
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

        
	def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(), # 认证[MyAuthentication(),]
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    
    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        return [ auth() for auth in self.authentication_classes ]
    
def perform_authentication(self, request):

    request.user

会执行Request中def user()

def user(self):
	self._authenticate()
    
def _authenticate(self):
    for authenticator in self.authenticators:
        user_auth_tuple = authenticator.authenticate(self)	# 循环上面获取到的认证对象类列表,执行自定制的auhenticate()方法

流程分析:

1. 当前请求到来时,执行APIview dispatch方法,request = self.initialize_request()先进行新的request封装,其中封装了老request、认证类对象列表等。 
2. 然后执行 initial方法,先进行分页、再进行认证执行 perform_authentication()  --- request.user
3.执行Request中def user(), user中循环认证类对象列表,执行每个对象的 def authenticate()(重写的方法),有三种返回方式:	 
    - 元组:认证通过
    - None:进行下个类的认证
    - 主动抛出异常:认证失败
下面两种方式可以触发第三步的认证:
	request.user 	能够获取当前登录用户对象
	request.auth	获取toke
posted @ 2019-11-28 21:26  SensorError  阅读(174)  评论(0编辑  收藏  举报