Loading

认证组件及源码分析

认证组件

​ 用于判断用户是否登录

简单使用

# 1.创建一个任意名字的py文件

# 2.导入认证类
from rest_framework.authentication import BaseAuthentication

# 3.写一个类继承它并且重写authenticate方法
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        token = request.META.get('HTTP_TOKEN')
        user_token = models.User_token.objects.filter(token=token).first()
        if user_token:
            return user_token.user, token
        else:
            raise AuthenticationFailed('请先登录')

# 4.在views.py导入这个自己写的类
from .authentication import LoginAuth

# 5.局部使用 在视图类下写authentication_classes属性,并且将自己写的认证类加到这个列表
class UserOperation():
    authentication_classes = [LoginAuth]
    
# 6.全局使用 在settings.py文件下配置REST_FRAMEWORK 
	REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':[
        'app01.auth.Login_authentication'
    ]
}
    
# 7.局部禁用 在某个想要禁用的视图类下定义列表为空
authentication_classes = []

认证类源码解析

​ 在视图类执行as_view()时会先到dispath()封装一个新的request

dispatch

def dispatch(self, request, *args, **kwargs):
    self.args = args
    self.kwargs = kwargs
    # 通过initialize_request封装新的request 
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers  # deprecate?

initialize_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(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )

get_authenticators

def get_authenticators(self):
    # 会通过遍历这个authentication_classes可迭代对象来以此调用里面的认证类对象
    # 这就是为什么我们需要在视图类里面定义这么一个列表或者元组
    return [auth() for auth in self.authentication_classes]

回到dispatch方法里面,查看三大认证操作

initial

def initial(self, request, *args, **kwargs):
	# 这三行代码进行了三大认证,点到perform_authentication里面看一看
    self.perform_authentication(request)
    self.check_permissions(request)
    self.check_throttles(request)

perform_authentication

def perform_authentication(self, request):
	# 就这么一行代码 看不出什么
    # 要想知道user是什么 从哪里来,就要去看看这个request的类是这么定义的
    # 当前这个request是经过Request包装过的新的request
    # 所以接下来去看看Request()这个类
    request.user

Request

发现user是一个包装成属性的方法

@property
def user(self):
    # 如果当前request没有_user这个属性,就执行_authenticate方法
    if not hasattr(self, '_user'):
        # 做了一个异常捕获
        with wrap_attributeerrors():
            self._authenticate()
    # 最后是返回了一个_user 说明_authenticate一定对_user赋值了
    return self._user

# 所以接下来点到_authenticate方法看一看

_authenticate方法

def _authenticate(self):
    # authenticators是实例化request对象时传入的参数,
    # 他是一个列表,列表里面是一个个认证类的实例
    for authenticator in self.authenticators:
        try:
            # 如果没有东西就会被异常捕获
            user_auth_tuple = authenticator.authenticate(self)
        except exceptions.APIException:
            self._not_authenticated()
            raise
		
        # 如果user_auth_tuple非空,就说明认证类里面的authenticate方法返回东西了
        if user_auth_tuple is not None:
            # 把认证类实例赋值给_authenticator
            self._authenticator = authenticator
            # 分别把值赋给user和auth
            # 也就是此时 request.user 就有值了
            self.user, self.auth = user_auth_tuple
            return
	
    # 如果没有报错,且没有返回元组,那么就执行了这么个玩意
    self._not_authenticated()
    
# 下面点进_not_authenticated

_not_authenticated

def _not_authenticated(self):
    self._authenticator = None
	# 如果配置文件配置了这个对象
    if api_settings.UNAUTHENTICATED_USER:
        # 就会执行某个函数,然后把返回值赋给user
        # 这个函数点进去看就会发现时执行了__str__方法然后返回了个字符串AnonymousUser
        # 也就是匿名用户的意思
        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

手动设置user

@user.setter
def user(self, value):
	# 这段源码解释了
    # 当手动设置user对象的时候
    # 还会把老的request.user 也设置成当前设置的user对象
    self._user = value
    self._request.user = value

总结

​ 当请求来的时候会执行dispach方法initialize_request方法包装新的request对象

​ Request会传入authenticators=self.get_authenticators(),如果你定义了序列化类,就会实例化这个类,把这个对象加到一个列表里,如果没有就不会触发校验

​ 这时候新的request对象已经生成好了,然后视图类对象会执行initial方法,这里面会触发perform_authentication方法进行认证,

​ 这个方法会执行request.user,然后执行Request类的_authenticate方法,这里就会根据你的序列化类的authenticate方法的返回值给request.user和request.auth赋值。

posted @ 2024-04-21 21:58  HuangQiaoqi  阅读(5)  评论(0编辑  收藏  举报