drf源码_认证

1、认证函数源码分析

1.1 用途

在开发API过程中,有些功能需要登录才能访问,有些无需登录。drf中的认证组件主要就是用来实现此功能。

关于认证组件,我们用案例的形式,先来学习常见的用用场景,然后再来剖析源码。
项目要开发100个接口,其中1个无需登录接口、98个必须登录才能访问的接口、1个公共接口(未登录时显示公共/已登录时显示个人信息)。

原来的认证信息只能放在URL中传递,如果程序中支持放在很多地方,例如:URL中、请求头中等。

认证组件中,如果是使用了多个认证类,会按照顺序逐一执行其中的authenticate方法

  • 返回None或无返回值,表示继续执行后续的认证类
  • 返回 (user, auth) 元组,则不再继续并将值赋值给request.user和request.auth
  • 抛出异常 AuthenticationFailed(...),认证失败,不再继续向后走

1.2 分析

源码链路:
1、认证函数执行步骤

称 APIView 为 A Request为R,因为自定义的视图类,基本上实例化方法都继承A所以,后面都以 A代替 实例化视图类为obj1, 实例化Request类为r1

ob1.dispatch() >> 代码入口,实例化视图类调用

obj1. initialize_request >> 把认证类列表 封装到request类,实例化视图类调用

obj1.get_authenticators >> 返回实例化对象的认证类列表,实例化视图类调用

obj1.initial >> 实例化视图类调用

obj1.perform_authentication >> 实例化视图类调用

r1.user >> 实例化Request调用

r1._authenticate >> 实例化Request调用

authenticate(r1) 实例化Request当做参数传入自定义的 authenticate 函数

源码分析
# 在视图类中,如果我们重写authentication_classes,则以重写为准,本质就是继承父类重写了类属性,如果不重写authentication_classes,那么就继承APIView 中的 authentication_classes 属性,而authentication_classes默认是写在api_settings配置中,所以如果要全局使用相同的认证组件,可以直接在配置文件中配置就可以
class OrderView(APIView):
    authentication_classes = [MyAuthentication, ]

    def get(self, request):
        pass

# 源码分析,(下面代码不讲究python格式,纯粹是笔记)
class APIView(View):
    # 默认读取配置文件中 DEFAULT_AUTHENTICATION_CLASSES 认证类
    # 一般配置的时候是以一个列表进行配置
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
 
#认证类组件也是从dispatch 为入口,只摘取部分关键代码,简化代码
       def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        #########  start: initialize_request 源码 ####################
         def initialize_request(self, request, *args, **kwargs):
          parser_context = self.get_parser_context(request)
          return Request(
            request,
            parsers=self.get_parsers(),
             # authenticators是对应各个认证类的实例化
            authenticators=self.get_authenticators(),
            #########  start: get_authenticators 源码 ####################
            def get_authenticators(self):
              #返回一个实例化的认证类列表
        		return [auth() for auth in self.authentication_classes]
            #########  end: get_authenticators 源码 ####################
            
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
         #########  end: initialize_request 源码 ####################
        
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)
             #########  start: initial 源码 ####################
                def initial(self, request, *args, **kwargs):
					'''省略部分代码'''
                    self.perform_authentication(request)
                    
                     #########  start: perform_authentication 源码#########
                         def perform_authentication(self, request):
        					request.user
                             #########  start: request.user 源码##########
                                @property
    							def user(self):
       								 if not hasattr(self, '_user'):
            							with wrap_attributeerrors():
                							self._authenticate()
                         #########  start: _authenticate 源码##########
                        
                        def _authenticate(self):
                                # 遍历每个认证类
                                for authenticator in self.authenticators:
                                    try:
                                        # 对drf的request进行认证
                                        user_auth_tuple = 
                                        # ****画重点**** 下面的self就是Request实例化的类
                                        authenticator.authenticate(self)
                                    except exceptions.APIException:
                                        self._not_authenticated()
                                        raise

                                if user_auth_tuple is not None:
                                    self._authenticator = authenticator
                                    self.user, self.auth = user_auth_tuple
                                    return

       							 self._not_authenticated()
                         #########  end: _authenticate 源码##########                  
                                            
                                            
        								return self._user

                            #########  end: request.user 源码##########
                            
                     #########  end: perform_authentication 源码##########
                    self.check_permissions(request)
                    self.check_throttles(request) 
             #########  end: initial 源码 ####################
            
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

认证类的使用

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

from api import models

# 类BaseAuthentication源码

class BaseAuthentication:
    """
    All authentication classes should extend BaseAuthentication.
    """

    # NotImplementedError 表示必须被重新定义,否则会调用authenticate然后报错
    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        raise NotImplementedError(".authenticate() must be overridden.")
	
    # 可以被重新定义,也可以不被重新定义
    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        """
        pass
    
    
####  认证Request下源码
    
   def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        # authenticator是自定义的 authenticator 类
        for authenticator in self.authenticators:
            try:
                # 使用自定义的authenticate 函数认证request
                # user_auth_tuplef返回的结果,如果报错,错误將会被抛出
                ## 
                ## ***** 画重点****,这个地方self本身指的就是 Request实例
                ## ***所以就传了request进去了*** 
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise
			# user_auth_tuple如果是None则表示认证没有通过,然后下一个
            # 认证函数进行认证,有一认证函数通过则表示认证通过,有一个
            # 认证函数出错,则就报错
            # 认证通过后 user_auth_tuple 通常是一个元组的形式赋值给self.user,
            # self.auth
            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

    def _not_authenticated(self):
        self._authenticator = None
		
        # 將匿名用户user设置为None
        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER()
        else:
            self.user = None

        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN()
        else:
            self.auth = None



#  使用认证组件

class QueryParamsAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get("token")
        if not token:
            # 什么都没有返回,相当于返回None
            return

        user_object = models.UserInfo.objects.filter(token=token).first()
        if user_object:
            return user_object, token  # request.user = 用户对象; request.auth = token

    # 这个先不管,不重要
    def authenticate_header(self, request):
        # return 'Basic realm="API"'
        return "API"


class HeaderAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.META.get("HTTP_AUTHORIZATION")
        if not token:
            return
        user_object = models.UserInfo.objects.filter(token=token).first()
        if user_object:
            return user_object, token  # request.user = 用户对象; request.auth = token

        return

    def authenticate_header(self, request):
        # return 'Basic realm="API"'
        return "API"


# 当前面认证都没有通过时,可以直接自定义authenticate,抛出错误
class NoAuthentication(BaseAuthentication):
    def authenticate(self, request):
        raise AuthenticationFailed({"status": False, 'msg': "认证失败"})

    def authenticate_header(self, request):
        return "API"

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值