zoukankan      html  css  js  c++  java
  • 6drf认证权限频率

    为了方便接下来的学习,我们创建一个新的子应用 opt

    python manage.py startapp opt
    

    因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员.

    python3 manage.py makemigrations
    python3 manage.py migrate
    python3 manage.py createsuperuser
    

    1557276390641

    创建管理员以后,访问admin站点,先修改站点的语言配置

    settings.py

    LANGUAGE_CODE = 'zh-hans'  # 中文
    
    TIME_ZONE = 'Asia/Shanghai' # 时区是亚洲上海
    
    USE_I18N = True # 国际化
    
    USE_L10N = True # 本地化
    
    USE_TZ = True # 数据库是否使用TIME_ZONE,True表示使用上海的时区,False表示不使用,使用UTC时间,然后转成上海,会差8个小时
    

    1553043081445

    访问admin 站点效果:

    1553043054133

    一 认证Authentication

    1.1 自定义认证方案

    1.1.1 编写models

    # models.py
    class User(models.Model):
        username=models.CharField(max_length=32)
        password=models.CharField(max_length=32)
        user_type=models.IntegerField(choices=((1,'超级用户'),(2,'普通用户'),(3,'二笔用户')))
    
    class UserToken(models.Model):
        user=models.OneToOneField(to='User')
        token=models.CharField(max_length=64)
    

    1.1.2 新建认证类

    from rest_framework.authentication import BaseAuthentication
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if token_obj:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    

    1.1.3 编写视图

    def get_random(name):
        import hashlib
        import time
        md=hashlib.md5()
        md.update(bytes(str(time.time()),encoding='utf-8'))
        md.update(bytes(name,encoding='utf-8'))
        return md.hexdigest()
    class Login(APIView):
        def post(self,reuquest):
            back_msg={'status':1001,'msg':None}
            try:
                name=reuquest.data.get('name')
                pwd=reuquest.data.get('pwd')
                user=models.User.objects.filter(username=name,password=pwd).first()
                if user:
                    token=get_random(name)
                    models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                    back_msg['status']='1000'
                    back_msg['msg']='登录成功'
                    back_msg['token']=token
                else:
                    back_msg['msg'] = '用户名或密码错误'
            except Exception as e:
                back_msg['msg']=str(e)
            return Response(back_msg)
    
    
    
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
    

    1.1.4 全局使用

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",]
    }
    

    1.1.5 局部使用

    #局部使用,只需要在视图类里加入:
    authentication_classes = [TokenAuth, ]
    

    1.2 内置认证方案(需要配合权限使用)

    可以在配置文件中配置全局默认的认证方案

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.SessionAuthentication',  # session认证
            'rest_framework.authentication.BasicAuthentication',   # 基本认证
        )
    }
    

    也可以在每个视图中通过设置authentication_classess属性来设置

    from rest_framework.authentication import SessionAuthentication, BasicAuthentication
    from rest_framework.views import APIView
    
    class ExampleView(APIView):
        # 类属性
        authentication_classes = [SessionAuthentication, BasicAuthentication]
        ...
    

    认证失败会有两种可能的返回值:

    • 401 Unauthorized 未认证
    • 403 Permission Denied 权限被禁止

    二 权限Permissions

    权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

    • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
    • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

    2.1 自定义权限

    2.1.1 编写权限类

    # 限制只有超级用户能访问
    from rest_framework.permissions import BasePermission
    class UserPermission(BasePermission):
        message = '不是超级用户,查看不了'
        def has_permission(self, request, view):
            # user_type = request.user.get_user_type_display()
            # if user_type == '超级用户':
            # 权限在认证之后,所以能取到user
            user_type = request.user.user_type
            print(user_type)
            if user_type == 1:
                return True
            else:
                return False
    

    2.1.2 全局使用

    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",],
        "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
    }
    

    2.1.3 局部使用

    # 局部使用只需要在视图类里加入:
    permission_classes = [UserPermission,]
    

    2.1.4 说明

    如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部
    - `.has_permission(self, request, view)`
      是否可以访问视图, view表示当前视图对象
    
    - `.has_object_permission(self, request, view, obj)`
      是否可以访问数据对象, view表示当前视图, obj为数据对象
    

    2.2 内置权限

    2.2.1 内置权限类

    from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly
    - AllowAny 允许所有用户
    - IsAuthenticated 仅通过认证的用户
    - IsAdminUser 仅管理员用户
    - IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的只能查看数据。
    

    2.2.2 全局使用

    可以在配置文件中全局设置默认的权限管理类,如

    REST_FRAMEWORK = {
        ....
        
        'DEFAULT_PERMISSION_CLASSES': (
            'rest_framework.permissions.IsAuthenticated',
        )
    }
    

    如果未指明,则采用如下默认配置

    'DEFAULT_PERMISSION_CLASSES': (
       'rest_framework.permissions.AllowAny',
    )
    

    2.2.3 局部使用

    也可以在具体的视图中通过permission_classes属性来设置,如

    from rest_framework.permissions import IsAuthenticated
    from rest_framework.views import APIView
    
    class ExampleView(APIView):
        permission_classes = (IsAuthenticated,)
        ...
    

    2.2.4 实际操作

    # 创建超级用户,登陆到admin,创建普通用户(注意设置职员状态,也就是能登陆)
    # 全局配置IsAuthenticated
    # setting.py
    'DEFAULT_PERMISSION_CLASSES': (
            'rest_framework.permissions.IsAuthenticated',
        )
    # urls.py
     path('test/', views.TestView.as_view()),
    # views.py
    class TestView(APIView):
        def get(self,request):
            return Response({'msg':'个人中心'})
    # 登陆到admin后台后,直接访问可以,如果没登陆,不能访问
    
    ##注意:如果全局配置了
    rest_framework.permissions.IsAdminUser
    # 就只有管理员能访问,普通用户访问不了
    

    三 限流Throttling

    可以对接口访问的频次进行限制,以减轻服务器压力。

    一般用于付费购买次数,投票等场景使用.

    3.1 自定义频率类

    3.1.1 编写频率类

    # 自定义的逻辑
    #(1)取出访问者ip
    #(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
    #(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
    #(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
    #(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
    class MyThrottles():
        VISIT_RECORD = {}
        def __init__(self):
            self.history=None
        def allow_request(self,request, view):
            #(1)取出访问者ip
            # print(request.META)
            ip=request.META.get('REMOTE_ADDR')
            import time
            ctime=time.time()
            # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
            if ip not in self.VISIT_RECORD:
                self.VISIT_RECORD[ip]=[ctime,]
                return True
            self.history=self.VISIT_RECORD.get(ip)
            # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
            while self.history and ctime-self.history[-1]>60:
                self.history.pop()
            # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
            # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
            if len(self.history)<3:
                self.history.insert(0,ctime)
                return True
            else:
                return False
        def wait(self):
            import time
            ctime=time.time()
            return 60-(ctime-self.history[-1])
    

    3.1.2 全局使用

    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES':['app01.utils.MyThrottles',],
    }
    

    3.1.3 局部使用

    #在视图类里使用
    throttle_classes = [MyThrottles,]
    

    3.2 内置频率类

    3.2.1 根据用户ip限制

    #写一个类,继承自SimpleRateThrottle,(根据ip限制)
    from rest_framework.throttling import SimpleRateThrottle
    class VisitThrottle(SimpleRateThrottle):
        scope = 'luffy'
        def get_cache_key(self, request, view):
            return self.get_ident(request)
    #在setting里配置:(一分钟访问三次)
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_RATES':{
            'luffy':'3/m'  # key要跟类中的scop对应
        }
    }
    
    # 可以全局使用,局部使用
    

    了解:错误信息中文显示

    class Course(APIView):
        authentication_classes = [TokenAuth, ]
        permission_classes = [UserPermission, ]
        throttle_classes = [MyThrottles,]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
        def throttled(self, request, wait):
            from rest_framework.exceptions import Throttled
            class MyThrottled(Throttled):
                default_detail = '傻逼啊'
                extra_detail_singular = '还有 {wait} second.'
                extra_detail_plural = '出了 {wait} seconds.'
            raise MyThrottled(wait)
    

    3.2.2 限制匿名用户每分钟访问3次

    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.AnonRateThrottle',
        ),
        'DEFAULT_THROTTLE_RATES': {
            'anon': '3/m',
        }
    }
    # 使用 `second`, `minute`, `hour` 或`day`来指明周期。
    # 可以全局使用,局部使用
    

    3.2.3 限制登陆用户每分钟访问10次

    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.UserRateThrottle'
        ),
        'DEFAULT_THROTTLE_RATES': {
            'user': '10/m'
        }
    }
    # 可以全局使用,局部使用
    

    3.2.4 其他

    1) AnonRateThrottle

    限制所有匿名未认证用户,使用IP区分用户。

    使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次

    2)UserRateThrottle

    限制认证用户,使用User id 来区分。

    使用DEFAULT_THROTTLE_RATES['user'] 来设置频次

    3)ScopedRateThrottle

    限制用户对于每个视图的访问频次,使用ip或user id。

    例如:

    class ContactListView(APIView):
        throttle_scope = 'contacts'
        ...
    
    class ContactDetailView(APIView):
        throttle_scope = 'contacts'
        ...
    
    class UploadView(APIView):
        throttle_scope = 'uploads'
        ...
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.ScopedRateThrottle',
        ),
        'DEFAULT_THROTTLE_RATES': {
            'contacts': '1000/day',
            'uploads': '20/day'
        }
    }
    

    实例

    全局配置中设置访问频率

    'DEFAULT_THROTTLE_RATES': {
        'anon': '3/minute',
        'user': '10/minute'
    }
    from rest_framework.authentication import SessionAuthentication
    from rest_framework.permissions import IsAuthenticated
    from rest_framework.generics import RetrieveAPIView
    from rest_framework.throttling import UserRateThrottle
    
    class StudentAPIView(RetrieveAPIView):
        queryset = Student.objects.all()
        serializer_class = StudentSerializer
        authentication_classes = [SessionAuthentication]
        permission_classes = [IsAuthenticated]
        throttle_classes = (UserRateThrottle,)
    
  • 相关阅读:
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之六 多点触控
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之九 定位
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之七 重力感应
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之五 保存数据的几种方式
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之八 照相机
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之三 Application 配置详解
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之四 打开与关闭应用程序是的保存数据
    ADOBE FLASH BUILDER 4.6 IOS 开发之部署与调试
    [译] 高性能JavaScript 1至5章总结
    页签及盒子的web标准实现
  • 原文地址:https://www.cnblogs.com/oysq/p/15648801.html
Copyright © 2011-2022 走看看