Django Rest Framework之认证

代码基本结构

  url.py:python

from django.conf.urls import url, include
from web.views.s1_api import TestView
 
urlpatterns = [
    url(r'^test/', TestView.as_view()),
]

   views.py:web

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions


class TestAuthentication(BaseAuthentication):
    def authenticate(self, request):
    '''
    认证代码编写区域
    '''
    return (用户,用户Token)

    def authenticate_header(self, request):
        # 验证失败时,返回的响应头WWW-Authenticate对应的值
        pass  


class TestView(APIView):
    authentication_classes = [TestAuthentication, ]  

    def get(self, request, *args, **kwargs):
        pass

    
     def post(self, request, *args, **kwargs):
        pass

        '''
        等等一系列的视图功能方法
        '''

   说明:

    1)在authenticate方法的返回值是一个元组,元组中第一个元素是用户名,第二个元素是认证数据token。这个返回值会在咱们的视图类中经过request.user 和 request.auth获取到。具体为何是这两个值,会在后面的源码分析中说明。django

    2)认证的返回值有三种状况:编程

      返回元组(如(1)中所述):认证成功api

      返回None:处理下一个认证类ide

      抛出异常:认证失败源码分析

    3)上面的基本结构是作局部的类的认证方式,若是相对绝大多数的类作认证,那么能够经过全局认证的方式实现。该方法在下文中介绍。post

    4)authentication_classes 属性变量是一个列表,列表元素是类,通常状况只使用一个认证类。     url

源码分析

  1) 为何要使用authentication_classes 属性变量?

  

   python 的面向对象编程中,咱们首先要执行的方法确定是dispatch方法,因此咱们的分析入口就是dispatch方法,在dispatch方法中,能够看到,经过initialize_request方法将django原生的request进行了一次封装。由initialize_request方法的实现过程能够看出,将其封装实例化成了一个Request对象。而authenticators属性就是认证属性。spa

 

   

  经过查看get_authenticators方法,能够知道,它的返回值是一个列表生成式,而这个列表生成式中所用的就是咱们在认证类中赋值authenticatin_classes属性变量。在查找该变量的定义位置,就看到了它是经过settings配置文件来实现赋值的,除非,在子类中将其赋值。咱们的代码就是这样作的。同时,也能够看出,咱们能够修改settings配置文件来为全局定义认证规则。

2)为何要认证类中要使用authenticate方法?

   

   

  回到前面说是的dispatch方法来,在作完了对django原生的request的封装和实例化后,紧接着就会开始认证(try...中,捕获异常,若是没有捕获到异常,说明认证成功,就会继续执行下面的反射过程)。认证的过程就包含在上图中的inital方法中,有图可知,是经过perform_authentication方法实现的认证。

   

   

  在perform_authentication方法中能够看到,只调用了一个request.user,而这个user必定是方法,不会是属性变量,由于若是是属性变量,那么就必定有语法错误,变量必定是要赋值的,不可能孤零零的写到那里。咱们在源码中找到它,就明白了,之因此它能这么写,就是由于有了property装饰器。在user方法中找到_authenticate方法,这就是认证的方法。

 

   在这个方法中,一切答案都就找到了。首先看authenticators,是否是很眼熟,没错它就是前面说的,封装和实例化原生request的Request类中所定义的属性变量。在实例化时,咱们就将authentication_classes列表的值经过get_authenticators方法中的列表生成式赋值给了authenticators。再往下看,authenticator.autheneicate(self)中的authenticator是否是就是咱们本身定义的认证类,而它在源码中要作“.authenticate(self)”的操做,那天然而然,咱们定义的认证类中要实现这个方法了。

  3)为何认证成功后的返回值在request.user和request.auth中?

  由 2)中最后一个图可知,当咱们认证成功后会执行“self.user, self.auth = user_auth_tuple”代码,咱们在认证类定义的方法authenticate的返回值就保存在 user_auth_tuple中,因此咱们经过request.user 和 request.auth 就能够获取到了。

实例

from django.conf.urls import url, include
from web.viewsimport TestView

urlpatterns = [
    url(r'^test/', TestView.as_view()),
]
urls.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions

token_list = [
    'sfsfss123kuf3j123',
    'asijnfowerkkf9812',
]


class TestAuthentication(BaseAuthentication):
    def authenticate(self, request):
        """
        用户认证,若是验证成功后返回元组: (用户,用户Token)
        :param request: 
        :return: 
            None,表示跳过该验证;
                若是跳过了全部认证,默认用户和Token和使用配置文件进行设置
                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
            (user,token)表示验证经过并设置用户名和Token;
            AuthenticationFailed异常
        """
        val = request.query_params.get('token')
        if val not in token_list:
            raise exceptions.AuthenticationFailed("用户认证失败")

        return ('登陆用户', '用户token')

    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.
        """
        # 验证失败时,返回的响应头WWW-Authenticate对应的值
        pass


class TestView(APIView):
    authentication_classes = [TestAuthentication, ]
    permission_classes = []

    def get(self, request, *args, **kwargs):
        print(request.user)
        print(request.auth)
        return Response('GET请求,响应内容')

    def post(self, request, *args, **kwargs):
        return Response('POST请求,响应内容')

    def put(self, request, *args, **kwargs):
        return Response('PUT请求,响应内容')
Views.py

扩展:全局认证

  若是要进行全局配置,由上面的源码分析可知,咱们只须要在配置文件中配置咱们存储到authentication_classes的值便可。但还要注意的是,在写配置文件时,要使用的是路径,因此最好在和views.py同级目录下新建一个文件夹(我习惯叫utils),再在该文件夹下新建一个认证文件(auth.py),将咱们的认证类都写到这里。

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES" :['api.utils.auth.MyAuthentication]     
}

    MyAuthentication类就是咱们写在utils文件夹下auth.py文件中的认证类。

  注意:若是有部分类不须要认证的话,能够在这里类中添加“authentication_classes = []”,便可。

相关文章
相关标签/搜索