zoukankan      html  css  js  c++  java
  • DAY99

    一、认证组件

    1.使用

    # 模型层
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
    
    
    class UserToken(models.Model):
        user = models.OneToOneField(to='User')
        token = models.CharField(max_length=64)
    
    #myAuth.py
    from app01 import models
    from rest_framework.exceptions import APIException
    from rest_framework.authentication import BaseAuthentication
    
    class Auth(BaseAuthentication):
        def authenticate(self,request):
            # 包装后的request对象,请求来的所有东西都能拿出来
            token = request.GET.get('token')
            ret = models.UserToken.objects.filter(token=token).first()
            # 如果有值,说明登录过了,而且带的随机字符串也是正确的
            # 如果认证通过,需要返回东西,如果认证不通过,要抛异常
            if ret:
                # 返回一个元组如果返回None,就会是一个匿名用户
                return ret.user,ret
            else:
                # 如果没有值,抛异常
                raise APIException('您没有登录')
    
    from app01.mySer import *
    import uuid
    
    # 登陆视图
    class Login(APIView):
        def post(self, request):
            response = {'status': 200, 'msg': '登录成功'}
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            user = models.User.objects.filter(name=name, pwd=pwd).first()
            if user:
                token = uuid.uuid4()
                # 登陆成功后,存入token表
                models.UserToken.objects.create(token=token, user=user)
                response['token'] = token
            else:
                response['status'] = 201
                response['msg'] = '添加失败'
            return JsonResponse(response, safe=False)
    
    # 局部使用,在所需的视图里局部使用
    class Books(APIView):
        # 登录后才能操作
        authentication_classes=[Auth,]
        def get(self, request):
            .......
        def post(self, request):
            .......
    class BooksDetail(APIView):
        authentication_classes = [Auth, ]
        def get(self, request):
            .......
        def post(self, request):
            .......
            
            
    # 全局使用
    # setting.py
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['app01.my_Auth.Auth']
    }
    
    # 全局使用后局部禁用
    # 在所属的试图里写一个空
    authentication_classes=[]
    

    2.源码分析

    # 第一步
    # APIView类
    def dispatch(self, request, *args, **kwargs):
    	........
        # 重点是这个,这是认证、频率相关的
        self.initial(request, *args, **kwargs)
    	........
    
    # 第二步
    # APIView类
    def initial(self, request, *args, **kwargs):
    	........
        # 这个就是认证
        self.perform_authentication(request)
        
        self.check_permissions(request)
        self.check_throttles(request)
    
    # 第三步
    # APIView类
    def perform_authentication(self, request):
    	# 这个request是已经封装好后的Request的对象
        request.user
    
    # 第四步
    # Request类
    @property
    def user(self):
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user
    
    # 第五步
    # Request类
    def _authenticate(self):
        # 从下面回到这里,就可以知道
        # self.authenticators=authentication_classes
        # 拿上面的例子举例
        # self.authenticators=[Auth, ];authenticator就是Auth
        for authenticator in self.authenticators:
            try:
    
    # 注意:authenticator.authenticate(self)中的self,由于是在Request类里,所以这个self就是Request实例化的对象request;
    # 所以:authenticator.authenticate(self)=Auth.authenticate(self,request)
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise
    
            if user_auth_tuple is not None:
                self._authenticator = authenticator
                # user_auth_tuple:authenticator.authenticate(self)的返回值,是个元组
                # 这就是一个元组的解压
                # self.user:request.user
                # self.auth:request.auth
                self.user, self.auth = user_auth_tuple
                return
    
       self._not_authenticated()
    
    
    # self.authenticators的来历
    # APIView类
    # self.authenticators 是Request实例化的时候传进来的参数self.get_authenticators()
    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)
    
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    
    
    # self.get_authenticators()的来历
    # APIView类
    def get_authenticators(self):
        # self.authentication_classes
        # 从子类找验证类:authentication_classes = [Auth, ]
        # 从父类APIView里找验证类:authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
        # 找到之后,循环并加上()执行
        return [auth() for auth in self.authentication_classes]
        
    

    3.不依靠数据库的token验证

    import hashlib
    # 设置token
    def set_token(id, salt='1'):
        md5 = hashlib.md5()
        md5.update(str(id).encode('utf-8'))
        md5.update(salt.encode('utf-8'))
        return md5.hexdigest() + '|' + str(id)
    
    # 校验token
    def check_token(token, salt='1'):
        tk = token.split('|')
        md5 = hashlib.md5()
        md5.update(str(tk[-1]).encode('utf-8'))
        md5.update(salt.encode('utf-8'))
        if tk[0] == md5.hexdigest():
            return True
        else:
            return False
    
    class Auth(BaseAuthentication):
        def authenticate(self, request):
            token = request.GET.get('token')
            # 如果GET里没有token,check_token里的split方法就会报错
            # 所以这里try一下异常
            try:
                ret = common.check_token(token)
                if ret:
                    return
                else:
                    # 抛异常
                    raise 
            except Exception as e:
                raise AuthenticationFailed('认证失败')
    
    class Login(APIView):
        def post(self, request):
            response = {'status': 100, 'msg': '登陆成功', 'token': None}
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            user = models.User.objects.filter(name=name, pwd=pwd).first()
            if user:
                # 传入用户id获得对应的token
                token = common.set_token(user.pk)
                response['token'] = token
            else:
                response['status'] = 200
                response['msg'] = '登录失败'
            return JsonResponse(response, safe=False)
    
    class Book(APIView):
        authentication_classes = [myAuthentication.Auth, ]
        def get(self, request):
            response = {'status': 100, 'msg': '查看成功', 'data': None}
            books = models.Book.objects.all()
            ret = mySerializers.BookSerializers(books,many=True)
            response['data']=ret.data
            return JsonResponse(response,safe=False)
    

    4.顺序

    认证类使用顺序:先用视图类中的验证类,再用settings里配置的验证类,最后用默认的验证类

    二、权限组件

    1.简单使用

    from rest_framework.permissions import BasePermission
    
    class VipPermission(BasePermission):
        message = '不是会员,查看不了'
    
        def has_permission(self, request, view):
            user_type = request.user.user_type
            if user_type == '1':
                return True
            else:
                return False
    
    class Book(APIView):
        # 局部使用
        permission_classes = [myPermission.VipPermission, ]
    
        def get(self, request):
            response = {'status': 100, 'msg': '查看成功', 'data': None}
            books = models.Book.objects.all()
            ret = mySerializers.BookSerializers(books, many=True)
            response['data'] = ret.data
            return JsonResponse(response, safe=False)
        
        
    # 全局使用
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES':['app01.myPermission.VipPermission']
    }
    
    # 全局使用中局部禁用
    class Book(APIView):
        permission_classes = []
    

    2.源码分析

    # 第一步
    # APIView类
    def dispatch(self, request, *args, **kwargs):
    	........
        # 重点是这个,这是认证、频率以及权限相关的
        self.initial(request, *args, **kwargs)
    	........
    
    # 第二步
    # APIView类
    def initial(self, request, *args, **kwargs):
    	........
        self.perform_authentication(request)
      	# 这就是 权限方法
        self.check_permissions(request)
        self.check_throttles(request)
    
    # 第三步
    # APIView类
    def check_permissions(self, request):
        # 这里的原理与认证类一致
    	for permission in self.get_permissions():
            # 有一点不同的是has_permission(request, self)中的self是APIView的self
            if not permission.has_permission(request, self):
                self.permission_denied(request, message=getattr(permission, 'message', None)
                )
                
                
    # self.get_permissions()的来历
    def get_permissions(self):
       return [permission() for permission in self.permission_classes]
    

    3.顺序

    权限类使用顺序:先用视图类中的权限类,再用settings里配置的权限类,最后用默认的权限类

  • 相关阅读:
    Java 传递参数时,传递一个变量快还是传递一个实体类?
    13 设计模式
    12 反射
    11.多线程&&并发
    10.输入输出
    9.异常Exception
    7.正则表达式
    5.数组
    6.常见对象
    上传本地项目到Github
  • 原文地址:https://www.cnblogs.com/xvchengqi/p/10116019.html
Copyright © 2011-2022 走看看