Python 学习笔记(二十)--Django REST Framework之认证

1. 主要代码

APIView---》dispatch方法--》initial(self, request, *args, **kwargs) ---》有认证、权限、频率的控制代码

        # Ensure that the incoming request is permitted
        ##认证组件:检验用户--游客、合法用户、非法用户
        ##游客:代表校验通过,直接进入下一步校验(权限校验)
        ##合法用户:代表校验通过,用户存储在request.user中,再进行下一步校验(权限校验)
        ##非法用户:代表校验失败,抛出异常,返回403权限异常结果。
        self.perform_authentication(request)
        ##权限组件:校验用户权限--必须登录、所有用户、登入只读游客自读、自定义用户角色
        ##认证通过,可以进入下一步校验(频率认证)
        ##认证失败,报错异常,返回403权限异常结果
        self.check_permissions(request)
        ##频率组件:限制视图接口被访问的频率次数--限制条件(IP、id、、唯一键)、频率周期时间(s、m、h)、频率次数(3/s)
        ##没有达到限制次数:正常访问接口
        ##达到限制次数:限制时间内不能访问,限制时间到达后,可以重新访问。
        self.check_throttles(request)

代码的上下文,请参考 《Python 学习笔记(十五)--Django REST Framework之Request

2. 方法perform_authentication的定义

    def perform_authentication(self, request):
        """
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        """
        request.user   ###去Request类中去查找,方法属性user

Request类中的user()方法属性

    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'): ###判断self这个对象有没有_user属性
            with wrap_attributeerrors():  ##上下文管理器
## 没用户,认证出用户 self._authenticate()
return self._user ##有用户,则直接返回用户

Request类中的user方法,刚开始,没有_user, 则调用_authenticate(self)

3. 调用到的基础方法

上面方法进一步调用到的基础方法

    def _authenticate(self): ##进行认证
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
## 遍历拿到一个个认证器,进行认证
##
self.authenticators 在视图类中配置的一堆认证类产生的认证类对象组成的 list
        for authenticator in self.authenticators: 
            try:
## 认证器(对象)调用认证方法authenticate(认证类对象self,request请求对象)
## 返回值:登录的用户与认证的信息组成的 tuple
## 该方法被try包裹,代表该方法会抛异常,抛异常代表认证失败 user_auth_tuple
= authenticator.authenticate(self) ###self 是request对象 except exceptions.APIException: self._not_authenticated() raise ## 返回值的处理 if user_auth_tuple is not None: self._authenticator = authenticator
## 如果有返回值,就将 登录用户 和 登录认证 分别保存到 request.user 和 request.auth中 self.user, self.auth
= user_auth_tuple return self._not_authenticated() def _not_authenticated(self): """ Set authenticator, user & authtoken representing an unauthenticated request. Defaults are None, AnonymousUser & None. """ self._authenticator = 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
self.authenticators 是我们在视图类中配置的一个个的认证类:authentication_classes = [认证类1,认证类2....],这是认证对象的列表

4. self.authenticators 为可迭代对象;注意,此时,self 是request对象。

def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None)
可以看出,authenticators 为传入参数。再进一步判断,什么时候传入的参数呢?
是 APIView--》def dispatch(self, request, *args, **kwargs)
中的 request = self.initialize_request(request, *args, **kwargs)
    # Dispatch methods

    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(),  ##列表,存放的类的对象
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
方法get_authenticators(self)的定义如下
def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        return [auth() for auth in self.authentication_classes]  ##列表生成式;列表中是一堆对象,是视图类中配置的authentication_classes=[类名]对象

读取的配置来源如下

class APIView(View):

    # The following policies may be set at either globally, or per-view.
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
    metadata_class = api_settings.DEFAULT_METADATA_CLASS
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

 5.重写认证类

如果重新认证类,其逻辑为: 继承BaseAuthentication,重写authenticate,认证的逻辑写在里面,认证通过,返回 self.user, self.auth 两个值,一个值最终给了Request对象的user,认证失败,则抛异常:APIException 或者是AuthenticationFailed.

  • 认证类执行认证的视图类中配置 authentication_classes = [自定义的认证类, ]
    • 认证类必须单独存放在py文件内,若防止在view内,使用全局配置时候,无法使用
    • 必须继承 BaseAuthentication
      • from rest_framework.authentication import BaseAuthentication
    • 认证类内必须重写 authenticate(self, request) 方法,request参数必须传入
    • 若后续有其他认证类需要执行,必须返回空!!
    • 若后续不无其他认证类需要执行,则返回两个值 - 对应DRF内Request对象User类内_authenticate方法执行
    • 若认证失败,抛出  exceptions.APIException 异常 
      • from rest_framework import exceptions
      • 或 from rest_framework.exceptions import AuthenticationFailed
 例子看参阅 https://www.cnblogs.com/clark1990/p/17152813.html
posted @ 2024-01-04 23:19  东山絮柳仔  阅读(55)  评论(0编辑  收藏  举报