博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
restful framework 认证源码流程
阅读量:6698 次
发布时间:2019-06-25

本文共 9315 字,大约阅读时间需要 31 分钟。

一、请求到来之后,都要先执行dispatch方法,dispatch方法方法根据请求方式的不同触发get/post/put/delete等方法

注意,APIView中的dispatch方法有很多的功能

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进行加工(添加数据)        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            # 第三步、执行:get/post/put/delete函数            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

 

二、上面是大致步骤,下面我们来具体分析一下,看每个步骤中都具体干了什么事

1、对request进行加工(添加数据)

我们来看看request里面都添加了那些数据

a、首先  request = self.initialize_request(request, *args, **kwargs)点进去,会发现:在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(),  #解析数据,默认的有三种方式,可点进去看            #self.get_authenticator优先找自己的,没有就找父类的            authenticators=self.get_authenticators(), #获取认证相关的所有类并实例化,传入request对象供Request使用            negotiator=self.get_content_negotiator(),            parser_context=parser_context        )

b、获取认证相关的类的具体   authenticators=self.get_authenticators(),

def get_authenticators(self):        """        Instantiates and returns the list of authenticators that this view can use.        """        #返回的是对象列表        return [auth() for auth in self.authentication_classes]  #[SessionAuthentication,BaseAuthentication]

c、查看认证的类:self.authentication_classes

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES  #默认的,如果自己有会优先执行直接的

d、接着走进api_settings

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)  #点击继承的DEFAULTS类
DEFAULTS = {    # Base API policies    'DEFAULT_AUTHENTICATION_CLASSES': (        'rest_framework.authentication.SessionAuthentication',   #这时候就找到了他默认认证的类了,可以导入看看        'rest_framework.authentication.BasicAuthentication'    ),

e、导入了类看看类里面具体干了什么

from rest_framework.authentication import SessionAuthenticationfrom rest_framework.authentication import BaseAuthentication

f、看到里面有个authenticate方法和authenticate_header方法

class BaseAuthentication(object):    """    All authentication classes should extend BaseAuthentication.    """    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

 具体处理认证,从headers里面能获取用户名和密码

class BasicAuthentication(BaseAuthentication):    """    HTTP Basic authentication against username/password.    """    www_authenticate_realm = 'api'    def authenticate(self, request):        """        Returns a `User` if a correct username and password have been supplied        using HTTP Basic authentication.  Otherwise returns `None`.        """        auth = get_authorization_header(request).split()        if not auth or auth[0].lower() != b'basic':            return None   #返回none不处理。让下一个处理        if len(auth) == 1:            msg = _('Invalid basic header. No credentials provided.')            raise exceptions.AuthenticationFailed(msg)        elif len(auth) > 2:            msg = _('Invalid basic header. Credentials string should not contain spaces.')            raise exceptions.AuthenticationFailed(msg)        try:            auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':')   #用partition切割冒号也包括        except (TypeError, UnicodeDecodeError, binascii.Error):            msg = _('Invalid basic header. Credentials not correctly base64 encoded.')            raise exceptions.AuthenticationFailed(msg)        userid, password = auth_parts[0], auth_parts[2]  # 返回用户和密码        return self.authenticate_credentials(userid, password, request)    def authenticate_credentials(self, userid, password, request=None):        """        Authenticate the userid and password against username and password        with optional request for context.        """        credentials = {            get_user_model().USERNAME_FIELD: userid,            'password': password        }        user = authenticate(request=request, **credentials)        if user is None:            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))        if not user.is_active:            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))        return (user, None)    def authenticate_header(self, request):        return 'Basic realm="%s"' % self.www_authenticate_realm

g、当然restfulframework默认定义了两个类。我们也可以自定制类,自己有就用自己的了,自己没有就去找父类的了,但是里面必须实现authenticate方法,不然会报错。

2、进行一下操作

  • 处理版权信息
  • 认证
  • 权限
  • 请求用户进行访问频率的限制

我们主要来看一下认证流程

认证流程:

a、首先 self.initial(request, *args, **kwargs)可以看到做了以下操作

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.        #2.1 处理版本信息        version, scheme = self.determine_version(request, *args, **kwargs)        request.version, request.versioning_scheme = version, scheme        # Ensure that the incoming request is permitted        #2.2 认证        self.perform_authentication(request)        # 2.3 权限        self.check_permissions(request)        # 2.4 请求用户进行访问频率的限制        self.check_throttles(request)

 b、我们先来看认证,self.perform_authentication(request) 具体干了什么,按住ctrl点击进去

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已经是加工后的request了

c、那么我们可以从视图里面导入一下Request,找到request对象的user方法

from rest_framework.views import Request

@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  #返回user

d、执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)

def _authenticate(self):        """        Attempt to authenticate the request using each authentication instance        in turn.        """        #循环对象列表        for authenticator in self.authenticators:            try:                #执行每一个对象的authenticate 方法                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  #返回一个元组,user,和auth,赋给了self,                # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了                return        self._not_authenticated()

 

e、在user_auth_tuple = authenticator.authenticate(self) 进行验证,如果验证成功,执行类里的authenticatie方法

 

f、如果用户没有认证成功:self._not_authenticated()

def _not_authenticated(self):        """        Set authenticator, user & authtoken representing an unauthenticated request.        Defaults are None, AnonymousUser & None.        """        #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置        self._authenticator = None  #        if api_settings.UNAUTHENTICATED_USER:            self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser        else:            self.user = None  # None 表示跳过该认证        if api_settings.UNAUTHENTICATED_TOKEN:            self.auth = api_settings.UNAUTHENTICATED_TOKEN()  # 默认值为:None        else:            self.auth = None    # (user, token)    # 表示验证通过并设置用户名和Token;    # AuthenticationFailed异常

3、执行get/post/delete等方法

4、对返回结果在进行加工

 

转载于:https://www.cnblogs.com/wanghaohao/p/8423149.html

你可能感兴趣的文章
Sql server优化50法
查看>>
使用Server 2008新GPO做驱动器映射
查看>>
解决eclipse + pydev 编译过程中有中文的问题
查看>>
IE打印空白
查看>>
Servlet执行时要实现的方法
查看>>
Linux+php+memcache+APC加速PHP网站
查看>>
技术分享连载(六十一)
查看>>
Citrix XenServer 池要求
查看>>
RHEL 5服务篇—常用网络配置命令
查看>>
不懂卷积神经网络?别怕,看完这几张萌图你就明白了
查看>>
PostgreSQL Frontend/Backend protocol (通信协议)
查看>>
Struts2教程9:实现自已的拦截器
查看>>
在 ActiveReports 中嵌入 Spread 控件
查看>>
Java网络编程从入门到精通(5):使用InetAddress类的getHostName方法获得域名
查看>>
从全息投影到全息平台,必须克服7个障碍
查看>>
烂泥:通过vsphere给esxi添加本地硬盘
查看>>
RabbitMQ实例教程:发布/订阅者消息队列
查看>>
mysql备份还原(视图、存储过程)
查看>>
JavaScript服务器端开发技术(对象属性的枚举与查询)
查看>>
Mware HA实战攻略之五VMwareHA测试验收
查看>>