DRF-认证 权限 频率组件

补充

  1 认证 权限 频率组件原理基本相同

  2 认证相关:

    session cookie token 认证相关的  这里用token

    token 1 有时间限制,超时则失效 2 每次登录更换一个token

  3 访问频率限制

    1 防止同一时间多次访问的黑客攻击,增加服务器压力。

  4 我们的解析 认证 权限 频率 是在用户get post等请求之前就做好了的

  5 uuid随机数模块,uuid.uuid4()获取随机数

 

认证 权限 频率组件操作流程

认证需要建立user表和token表

# 用户表
class User(models.Model):
    user=models.CharField(max_length=32)
    pwd=models.CharField(max_length=32)
    type=((1,"VIP"),(2,"SVIP"),(3,"SSSVIP"))
    user_type=models.IntegerField(choices=type)


# token表
class UserToken(models.Model):
    user=models.OneToOneField("User")
    token=models.CharField(max_length=128)

用户登录视图添加token

 

from app01.models import User,UserToken

class LoginView(APIView):
    """
    1000:成功
    1001:用户名或者密码错误
    1002:异常错误
    """
    def post(self,request):

       response = {"code": 1000, "msg": None, "user": None}
       try:
           print(request.data)
           user = request.data.get("user")
           pwd = request.data.get("pwd")

           user = User.objects.filter(user=user, pwd=pwd).first()
           import uuid
           random_str = uuid.uuid4()
           if user:

               UserToken.objects.update_or_create(user=user, defaults={"token": random_str})
               response["user"] = user.user
               response["token"] = random_str
           else:
               response["code"] = 1001
               response["msg"] = "用户名或者密码错误"

       except Exception as e:
           response["code"]=1002
           response["msg"]=str(e)


       return Response(response)

 

 

 

认证自定义的模块

其中继承 BaseAuthentication除了类本生加的功能外还继承了header方法,如果不继承需要自己写一个header方法,否则会报错!

from app01.models import UserToken
from rest_framework.exceptions import AuthenticationFailed

from rest_framework.authentication import BaseAuthentication

class UserAuth(BaseAuthentication):

    def authenticate(self,request):

        token=request.query_params.get("token")

        usertoken=UserToken.objects.filter(token=token).first()
        if usertoken:
              return usertoken.user,usertoken.token
        else:
            raise AuthenticationFailed("认证失败!")

权限组件自定义的模块

from rest_framework.permissions import AllowAny


class SVIPPermission(object):
    message="您没有访问权限!"
    def has_permission(self,request,view):
        if request.user.user_type >= 2:
            return True
        return False

 

频率组件自定义的模块

以一分钟访问3次为例

from rest_framework.throttling import BaseThrottle

VISIT_RECORD={}
class VisitThrottle(BaseThrottle):

    def __init__(self):
        self.history=None

    def allow_request(self,request,view):
        remote_addr = request.META.get('REMOTE_ADDR')
        print(remote_addr)
        import time
        ctime=time.time()

        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr]=[ctime,]
            return True

        history=VISIT_RECORD.get(remote_addr)
        self.history=history

        while history and history[-1]<ctime-60:
            history.pop()

        if len(history)<3:
            history.insert(0,ctime)
            return True
        else:
            return False

    def wait(self):
        import time
        ctime=time.time()
        return 60-(ctime-self.history[-1])

在全局中的定制

REST_FRAMEWORK={
    # 解析器组件
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
    ),
    # 认证组件
   'DEFAULT_AUTHENTICATION_CLASSES': (
        'app01.utils.auth_class.UserAuth',

    ),
    # 权限组件
    'DEFAULT_PERMISSION_CLASSES': (
         'app01.utils.permission_class.SVIPPermission',
    ),
    # 频率组件  
    'DEFAULT_THROTTLE_CLASSES': (),
}

在局部中的定制及在视图中的使用

# 导入自定义的认证功能类
from app01.utils.auth_class import UserAuth
# 导入自定义的权限功能类
from app01.utils.permission_class import SVIPPermission
# 导入自定义的频率功能类
from app01.utils.throttle_classes import VisitThrottle


from rest_framework.throttling import BaseThrottle
class VisitThrottle(BaseThrottle):
    def allow_request(self,request,view):
         """
         限制IP每分钟访问不能超过3次
         :param request:
         :param view:
         :return:
         """
         print(self.get_ident(request))
         remote_addr = request.META.get('REMOTE_ADDR')
         print("REMOTE_ADDR",remote_addr)
         return False




class BookView(APIView):
    # 认证
    # authentication_classes = [UserAuth]
    # 权限
    # permission_classes = [SVIPPermission]
    # 频率
    throttle_classes = [VisitThrottle]

    def get(self,request):
        '''
        查看所有书籍
        :param request:
        :return:
        '''

        print(request.user,request.auth)



        book_list=Book.objects.all()
        serializer=BookSerializer(book_list,many=True)
        return Response(serializer.data)

    def post(self,request):
        '''
        添加一条书籍
        :param request:
        :return:
        '''
        print(request.data)

        serializer=BookSerializer(data=request.data,many=False)

        if serializer.is_valid():
            serializer.save() # create操作

            return Response(serializer.data)
        else:
            return Response(serializer.errors)

class SBookView(APIView):

    def get(self,request,id):
        edit_obj=Book.objects.get(pk=id)
        serializer=BookSerializer(edit_obj,many=False)
        return Response(serializer.data)

    def put(self,request,id):
        edit_obj = Book.objects.get(pk=id)
        serializer=BookSerializer(data=request.data,instance=edit_obj)
        if serializer.is_valid():
            serializer.save() # edit_obj.update(request.data)
            return Response(serializer.data)
        else:
            return Response(serializer.errors)


    def delete(self,request,id):
        edit_obj = Book.objects.get(pk=id).delete()
        return Response("")    

以认证为例的源码解析

 

//用户访问,当经过dispath时
1 def dispatch(self, request, *args, **kwargs):
        self.initial(request, *args, **kwargs)
  initial()是我们的解析 认证 权限 频率功能
2 在initial函数中
    def initial(self, request, *args, **kwargs):
        # 执行认证功能
        self.perform_authentication(request)
        # 执行权限功能
        self.check_permissions(request)
        # 执行频率功能
        self.check_throttles(request)
3 我们走perform_authentication(request)认证功能
    def perform_authentication(self, request):
        request.user
    从这里我们要从request实例中找user方法
4 我们通过request实例对象找到它的类中的user方法
    def dispatch(self, request, *args, **kwargs):
        request = self.initialize_request(request, *args, **kwargs)
    def initialize_request(self, request, *args, **kwargs)
        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    class Request(object):
        def user(self):
            if not hasattr(self, '_user'):
                with wrap_attributeerrors():
                self._authenticate()
            return self._user
5 在_authenticate()中:
    def _authenticate(self):
        # 和解析器一样,获得[UserAuth()] 获得顺序:当前视图类下-->全局setting-->默认default
        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
                # 这里有个坑,如果返回元组,则直接结束_authenticate函数,不继续循环了!
                return
    这里如果不抛异常则进入下一个组件

 

 

 

 


posted @ 2018-09-20 15:22  神秘嘉宾7m  阅读(184)  评论(0编辑  收藏  举报