关于drf框架中的用户认证

本文介绍关于drf框架中的用户认证的源码流程

在drf框架中我们通过相关组件来实现用户认证,下面是导包的语句

javascript 复制代码
from rest_framework.authentication import BaseAuthentication

这段代码我来判断用户的请求头中是否传入了token信息来进行用户验证,当然这里可以自行修需要验证的内容

kotlin 复制代码
class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token=request.query_params.get("token")
        print(token)
        if not token:
            return
        user_object=models.Userinfo.objects.filter(token=token).first()
        if user_object:
            return user_object,token
        return

这段代码来判断请求头中有没有token

kotlin 复制代码
# 判断请求头是否有token
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
        return

下面这段代码是我们判断如果没有通过验证,将会返回某些认证信息,这里需要导入AuthenticationFailed包

ruby 复制代码
class NoAuthentication(BaseAuthentication):
    def authenticate(self, request):
        raise AuthenticationFailed({"code":10001,"msg":"认证失败"})

下面是思路梳理 一切的一切开始都从url开始,我们首先调用了as_view()方法,那么就仅需里面看看发生了什么

python 复制代码
def as_view(cls, **initkwargs):
    """
    Store the original class on the view function.

    This allows us to discover information about the view when we do URL
    reverse lookups.  Used for breadcrumb generation.
    """
    if isinstance(getattr(cls, 'queryset', None), models.query.QuerySet):
        def force_evaluation():
            raise RuntimeError(
                'Do not evaluate the `.queryset` attribute directly, '
                'as the result will be cached and reused between requests. '
                'Use `.all()` or call `.get_queryset()` instead.'
            )
        cls.queryset._fetch_all = force_evaluation

    view = super().as_view(**initkwargs)
    view.cls = cls
    view.initkwargs = initkwargs

    # Note: session based authentication is explicitly CSRF validated,
    # all other authentication is CSRF exempt.
    return csrf_exempt(view)

这里返回view,从17行我们可以知道他调用了父类的方法,进去查看一下

python 复制代码
def as_view(cls, **initkwargs):
    """Main entry point for a request-response process."""
    for key in initkwargs:
        if key in cls.http_method_names:
            raise TypeError(
                "The method name %s is not accepted as a keyword argument "
                "to %s()." % (key, cls.__name__)
            )
        if not hasattr(cls, key):
            raise TypeError(
                "%s() received an invalid keyword %r. as_view "
                "only accepts arguments that are already "
                "attributes of the class." % (cls.__name__, key)
            )

    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        self.setup(request, *args, **kwargs)
        if not hasattr(self, "request"):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        return self.dispatch(request, *args, **kwargs)

    view.view_class = cls
    view.view_initkwargs = initkwargs

    # __name__ and __qualname__ are intentionally left unchanged as
    # view_class should be used to robustly determine the name of the view
    # instead.
    view.__doc__ = cls.__doc__
    view.__module__ = cls.__module__
    view.__annotations__ = cls.dispatch.__annotations__
    # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
    # the dispatch method.
    view.__dict__.update(cls.dispatch.__dict__)

    # Mark the callback if the view class is async.
    if cls.view_is_async:
        markcoroutinefunction(view)

    return view

他返回的view值在第24行的dispatch里,这里我们来到他的apiview里面去查找dispatch方法 (注意这里的dispatch方法有很多都有,我们要看看是谁调用的这个方法,这里涉及面向对象的知识,不懂的可以去回顾一下)

python 复制代码
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.
    """
    self.args = args
    self.kwargs = kwargs
    request = self.initialize_request(request, *args, **kwargs)
    self.request = request
    self.headers = self.default_response_headers  # deprecate?

    try:
        self.initial(request, *args, **kwargs)

        # Get the appropriate handler method
        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

我们发现前面的request封装被封装成了一个新的对象,不同于原来的django中的request,现在封装成新的request对象,继承了原来的方法,但是也增加了新的内容,这里感兴趣的可以自己看看,这里不再说明,接着他在第13行进行了一个定义方法,我们进去查看一下

python 复制代码
def initial(self, request, *args, **kwargs):
    """
    Runs anything that needs to occur prior to calling the method handler.
    """
    self.format_kwarg = self.get_format_suffix(**kwargs)

    # Perform content negotiation and store the accepted info on the request
    neg = self.perform_content_negotiation(request)
    request.accepted_renderer, request.accepted_media_type = neg

    # Determine the API version, if versioning is in use.
    version, scheme = self.determine_version(request, *args, **kwargs)
    request.version, request.versioning_scheme = version, scheme

    # Ensure that the incoming request is permitted
    self.perform_authentication(request)
    self.check_permissions(request)
    self.check_throttles(request)

(这里的17,18,19行分别是认证组件,权限组件,节流组件) 进入17行我们来看一下

python 复制代码
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是什么 我们进去,发现def user函数,这里有个装饰器,不懂得再去回顾回顾,主要是这样就能够直接调用这个函数,同理这里我们也找到了auth方法,所以我们能够直接调用request.auth和request.user

python 复制代码
@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'):
        with wrap_attributeerrors():
            self._authenticate()
    return self._user
python 复制代码
@property
def auth(self):
    """
    Returns any non-user authentication information associated with the
    request, such as an authentication token.
    """
    if not hasattr(self, '_auth'):
        with wrap_attributeerrors():
            self._authenticate()
    return self._auth

self._authenticate()这个方法是什么呢,我们进去看看

python 复制代码
def _authenticate(self):
    """
    Attempt to authenticate the request using each authentication instance
    in turn.
    """
    for authenticator in self.authenticators:
        try:
            user_auth_tuple = 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()

这里的authenticators是我们创建的各个认证类,他通过循环遍历,然后查找authenticate方法,这里要求返回user,和auth两个参数,所以也就是我们一开始需要两个返回值的原因,之后便可以通过调用request.auth和request.user来获取数据了

相关推荐
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
AskHarries3 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
isolusion4 小时前
Springboot的创建方式
java·spring boot·后端
zjw_rp4 小时前
Spring-AOP
java·后端·spring·spring-aop
TodoCoder4 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
凌虚5 小时前
Kubernetes APF(API 优先级和公平调度)简介
后端·程序员·kubernetes
机器之心6 小时前
图学习新突破:一个统一框架连接空域和频域
人工智能·后端
.生产的驴7 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
顽疲7 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端
机器之心7 小时前
AAAI 2025|时间序列演进也是种扩散过程?基于移动自回归的时序扩散预测模型
人工智能·后端