• Django-restframework 源码之认证组件源码分析


    Django-restframework 源码之认证组件源码分析

    一 前言

    之前在 Django-restframework 的流程分析博客中,把最重要的关于认证、权限和频率的方法找到了。该方法是 APIView 的一个名为initial的类方法,也就是在 views 中定义的视图类方法,继承自APIView方法。该方法源码如下:

    那么当代码执行到这里时,最开始执行的是用户的认证,也就是perform_autnentication方法。下面来深入的分析一下在用户认证中具体是怎么执行的。

    二 用户认证执行流程

    进入查看该方法源码如下:

    1. 执行APIView.perform_authentication

    2. 执行 Request.user

    3. 执行Request._authenticate

    4. Request.authenticators

    5. APIView.initialize_request

    6. APIView.get_authticators

    7. api_settings.DEFAULT_AUTHENTICATION_CLASSES

    到这里就是查找APIView 配置的问题了,后面的DEFAULT_AUTHENTICATION_CLASSES是默认的认证类,该类定义在settings.py文件中。之后我会写一篇 Django 加载项目配置的博客,到时候详细分析一下,这会涉及到 python 的两种加载文件的方式,一种是 import;一种是使用importlib模块导入。

    三 自定义认证组件

    了解了 restframework 的认证流程,对于需要自定义认证组件其实很明了,就是自定义认证类,重写 authenticate 方法。不过这还不行,我们还需要进行一下配置。

    需求:在之前的项目中,我们需要在服务器中保存相关的 cookie 或 session 来进行用户身份校验,那么如何使用 restframework 的认证来实现该需求,使得既能校验身份,也可以不用在服务端保存用户的 cookie 或 session。

    首先不管 cookie 或 session 都是为了校验用户的,那么在这里我们可以使用一个随机字符串(加密后的),当客户端朝服务端发送请求时会携带该值,之后进行反解用来对比。

    1. urls.py

    url(r'^login/', views.Login.as_view()),
    

    2. Views.py

    # 获取 随机token值
    def get_token(id, salt='123'):
        md = hashlib.md5()
        md.update(bytes(str(id), encoding='utf-8'))
        md.update(bytes(salt, encoding='utf-8'))
    
        return md.hexdigest() + '|' + str(id)
    
    # 登陆视图类
    class Login(APIView):
    
        # def dispatch(self, request, *args, **kwargs):
        #     return super(Login, self).dispatch(request, *args, **kwargs)
    
        def post(self, request):
            response = {'status': 100, 'msg': None}
            name = request.data.get('name')
            password = request.data.get('password')
            print(name, password)
            user_obj = models.UserInfo.objects.filter(name=name, password=password).first()
            if user_obj:
                token = get_token(user_obj.pk)
                response['msg'] = '登陆成功'
                response['status'] = 100
                response['token'] = token
                print('111', token)
            else:
                response['msg'] = '用户名或密码错误'
            return Response(response)
        
    

    3. authenticate_classes.py

    # 校验 token
    def check_token(token, salt='123'):
        ls = token.split('|')
        md = hashlib.md5()
        md.update(bytes(ls[-1], encoding='utf-8'))
        md.update(bytes(salt, encoding='utf-8'))
        if md.hexdigest() == ls[0]:
            return True
        else:
            return False
    
    
    # 改写的认证类
    class BookAuth(BaseAuthentication):
    
        def authenticate(self, request):
            token = request.data.get('token')
            print('222', token)
            if token:
                succ = check_token(token)
                if succ:
                    print('333')
                    # user =
                    return
                else:
                    raise NotAuthenticated('认证失败')
            else:
                raise NotAuthenticated('请先登录')
    

    四 配置自定义认证类

    1. 局部配置

    假设一个功能需要登陆成功才可以使用,那么只需要在该视图类中定义一个参数authentication_classes

    class Book(APIView):
        # 配置该参数可以局部使用
        authentication_classes = [authticate_classes.BookAuth, ]
    
        def dispatch(self, request, *args, **kwargs):
            return super().dispatch(request, *args, **kwargs)
    
        def get(self, request, id):
            print(request.user, '444')
            response = {'status': 100, 'msg': None}
            book_obj = models.Book.objects.filter(pk=id).first()
            if book_obj:
                book_ser = myser.BookSer(book_obj, many=False)
                response['book'] = book_ser.data
            else:
                response['msg'] = '图书没有对象'
                response['status'] = 101
            return Response(response)
    

    2. 全局使用

    全局使用的话需要在项目 settings 中配置,如下:

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.authenticate_classes.BookAuth",]
    }
    

    这样对 views 中所有的请求方法都有效。因为所有的视图类都会加载 settings 中的配置。这些都是在dispatch方法中完成的。

    3. 局部禁用

    局部禁用的话只需要在视图类中定义一个空的authentication_classes

    authentication_classes = []
    
  • 相关阅读:
    【转】C++虚函数表
    vector的增长模式
    C++ 四种类型强制转换
    【转】new和malloc的区别
    C++堆和栈的区别
    C/C++中的内存分区
    mySQL__function课堂笔记和练习
    mySQL__storage课堂笔记和练习
    mySQL__Variable课堂笔记和练习
    mySQL__View课堂笔记和练习
  • 原文地址:https://www.cnblogs.com/zuanzuan/p/10433109.html
Copyright © 2020-2023  润新知