• $Django Rest Framework-认证组件,权限组件 知识点回顾choices,on_delete


    一 小知识点回顾

    #orm
    class UserInfo (models.Model):
        id = models.AutoField (primary_key=True)
        name = models.CharField (max_length=32)
        pwd = models.CharField (max_length=32)
        choices = ((0, '普通用户'), (1, 'vip用户'), (2, '年费vip'))
        user_type = models.IntegerField (choices=choices, default=0)
    #view
       获取汉字
       request.user.get_user_type_display()
    choices
    class Book (models.Model):
        # 表示外键关联到出版社表,当出版社表删除了该条数据,图书表中不删除,仅仅是把外键置空
        # 同时存在null=True,on_delete=models.SET_NULL
        publish = models.ForeignKey (to='Publish', to_field='id', null=True, on_delete=models.SET_NULL)
    dj2必须写on_delete,dj1默认models.CASCADE

    二 认证组件

    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import APIException
    from app01 import models
    from app01.get_token import get_token
    class Auth(BaseAuthentication):
        def authenticate(self,request):
            token=request.query_params.get('token')
            #存数据库的token
            # ret=models.UserToken.objects.filter(token=token).first()
            # 不用存的token
            if token:
                user_id=token.split('|')[1]
                token_=token.split('|')[0]
                ret=get_token(user_id)
                if ret==token_:
                    # return ret.user,ret
                    user = models.UserInfo.objects.filter (id=user_id).first ()
                    return user,user
                else:
                    raise APIException('你还没有登陆')
            else:
                raise APIException ('你还没有登陆')
    认证组件重点authenticate(self,request)返回元组(request.user,request.auth)或者异常
    #局部使用
    class Login(APIView):
        authentication_classes=[Auth,]
        def post(self,request):
            pass
    
    
    #全局使用 settings里面配置
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['app01.Myauthentication.Auth',],
       }
     class Login(APIView):
        #局部禁用认证组件
        authentication_classes=[]
        def post(self,request):
           pass
    局部使用,全局使用(局部禁用)
    import hashlib
    import time
    def get_token(xxx):
        # 存数据库的token
        # md5=hashlib.md5()
        # md5.update(xxx.encode('utf-8'))
        # md5.update(str(time.time()).encode('utf-8'))
        #不存数据库的token
        md5=hashlib.md5()
        md5.update('天王盖地虎xx蘑菇炖小鸡'.encode('utf-8'))
        md5.update(str(xxx).encode('utf-8'))
        md5.update('自古英雄爱美人'.encode('utf-8'))
        return md5.hexdigest()
    
    class Login(APIView):
        #局部禁用认证组件,setting定义全局
        authentication_classes=[]
         #局部使用认证组件
        #authentication_classes=[Auth,]
        def post(self,request):
            name=request.data.get('name')
            pwd=request.data.get('pwd')
            response={'status':100,'msg':'登陆成功'}
            try:
                ret=models.UserInfo.objects.get(name=name,pwd=pwd)
                # 存数据库的token
                # token = get_token (ret.name)
                # models.UserToken.objects.update_or_create(user=ret,defaults={'token':token})
                # 不用存的token
                token = get_token (ret.id)
                response['token']='{}|{}'.format(token,ret.id)
            except ObjectDoesNotExist:
                response['status']=101
                response['msg']='用户名或密码不存在'
            except Exception:
                response['status'] = 102
                response['msg'] = '未知错误'
            return JsonResponse(response,safe=False)
    Login

    三 权限组件(认证组件通过后可以拿到request.user)

    from rest_framework.permissions import BasePermission

    class Per(BasePermission):
        message='请先升级用户'
        def has_permission(self,request,view):
            user_type=request.user.user_type
            if user_type==1:
                return True
            return False
    权限组件重点has_permission(self,request,view)判断权限字段为vip返回False,不足返回True.message='请先升级用户'
    #1局部使用
    class Books(APIView):
        permission_classes=[Per,]
        def get(self,request):
            response={'status':100,'msg':'请求成功'}
            books=models.Book.objects.all()
            ser=Myserializers.Books(books,many=True)
            response['data']=ser.data
            return JsonResponse(response,safe=False)
    
    #2全局使用 settings里配置 
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['app01.Myauthentication.Auth',],
        'DEFAULT_PERMISSION_CLASSES': ['app01.Mypermission.Per', ]
    } 
    #配置好了全局默认使用
    class Books(APIView):
        def get(self,request):
            response={'status':100,'msg':'请求成功'}
            books=models.Book.objects.all()
            ser=Myserializers.Books(books,many=True)
            response['data']=ser.data
            return JsonResponse(response,safe=False)
    
        #局部禁用
        class Books(APIView):
        permission_classes=[]
        def get(self,request):
            response={'status':100,'msg':'请求成功'}
            books=models.Book.objects.all()
            ser=Myserializers.Books(books,many=True)
            response['data']=ser.data
            return JsonResponse(response,safe=False)
    局部使用,全局使用(局部禁用)

     源码剖析

    #一 Apiview的dispach方法
    把Apiview的认证列表 封装进了request对象里
    
    #二 Apiview执行认证方法
    #self.perform_authentication(request)   
        def perform_authentication(self, request):
            request.user  #调用了user方法
    
    #三 request.user方法
    @property
        def user(self):
            if not hasattr(self, '_user'):
                with wrap_attributeerrors():
                    self._authenticate()
            return self._user
    
    
    #四 self._authenticate()
        def _authenticate(self):
            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()
    认证分析
    #一 Apiview的self.check_permissions(request)方法
    #    self.get_permissions()为Apiview的权限对象列表
        def check_permissions(self, request):
            for permission in self.get_permissions():
                if not permission.has_permission(request, self):
                    self.permission_denied(
                        request, message=getattr(permission, 'message', None)
                    )
    权限分析

    认证组件源码实现方式

    总结:  as_view()闭包函数如返回view的内存地址 ,内部的view返回dispach的执行结果   

    1->apiview的as_view() 重用view的as_view() 返回了一个

    csrf_exempt(view)

    2->apiview自己的dispach方法内

    (重新包装request,调用了认证【返回request.user】权限频率方法,判断reques.method 在没在 view类下的请求方式列表内 )

    返回request.method.请求方式()/抛出异常执行结果执行

    3->apiview定义了

    authentication_classes地址列表 执行了自己的方法
    authenticators=self.get_authenticators()拿到一个个对象列表
    传入request类生对象
    4—>requst.user
    再request类中
    for循环列表对象
    调了列表对象类的
    ret=authenticator.authenticate(self) #self为request对象
    return self.user,self.auth







  • 相关阅读:

    python内存管理
    python-继承类执行的流程
    Redis-key的设计技巧
    Redis-误操作尝试恢复
    Python3之hashlib
    面相对象
    设计模式
    RESTful API规范
    Django中间件执行流程
  • 原文地址:https://www.cnblogs.com/3sss-ss-s/p/10110833.html
Copyright © 2020-2023  润新知