目录
一、认证(补充的一个点)
认证请求头

1 1 #!/usr/bin/env python 2 2 # -*- coding:utf-8 -*- 3 3 from rest_framework.views import APIView 4 4 from rest_framework.response import Response 5 5 from rest_framework.authentication import BaseAuthentication 6 6 from rest_framework.permissions import BasePermission 7 7 8 8 from rest_framework.request import Request 9 9 from rest_framework import exceptions 1010 1111 token_list = [ 1212 'sfsfss123kuf3j123', 1313 'asijnfowerkkf9812', 1414 ] 1515 1616 1717 class TestAuthentication(BaseAuthentication): 1818 def authenticate(self, request): 1919 """ 2020 用户认证,如果验证成功后返回元组: (用户,用户Token) 2121 :param request: 2222 :return: 2323 None,表示跳过该验证; 2424 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 2525 self._authenticator = None 2626 if api_settings.UNAUTHENTICATED_USER: 2727 self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户 2828 else: 2929 self.user = None 3030 3131 if api_settings.UNAUTHENTICATED_TOKEN: 3232 self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默认值为:None 3333 else: 3434 self.auth = None 3535 (user,token)表示验证通过并设置用户名和Token; 3636 AuthenticationFailed异常 3737 """ 3838 val = request.query_params.get('token') 3939 if val not in token_list: 4040 raise exceptions.AuthenticationFailed("用户认证失败") 4141 4242 return ('登录用户', '用户token') 4343 4444 def authenticate_header(self, request): 4545 """ 4646 Return a string to be used as the value of the `WWW-Authenticate` 4747 header in a `401 Unauthenticated` response, or `None` if the 4848 authentication scheme should return `403 Permission Denied` responses. 4949 """ 5050 pass 5151 5252 5353 class TestPermission(BasePermission): 5454 message = "权限验证失败" 5555 5656 def has_permission(self, request, view): 5757 """ 5858 判断是否有权限访问当前请求 5959 Return `True` if permission is granted, `False` otherwise. 6060 :param request: 6161 :param view: 6262 :return: True有权限;False无权限 6363 """ 6464 if request.user == "管理员": 6565 return True 6666 6767 # GenericAPIView中get_object时调用 6868 def has_object_permission(self, request, view, obj): 6969 """ 7070 视图继承GenericAPIView,并在其中使用get_object时获取对象时,触发单独对象权限验证 7171 Return `True` if permission is granted, `False` otherwise. 7272 :param request: 7373 :param view: 7474 :param obj: 7575 :return: True有权限;False无权限 7676 """ 7777 if request.user == "管理员": 7878 return True 7979 8080 8181 class TestView(APIView): 8282 # 认证的动作是由request.user触发 8383 authentication_classes = [TestAuthentication, ] 8484 8585 # 权限 8686 # 循环执行所有的权限 8787 permission_classes = [TestPermission, ] 8888 8989 def get(self, request, *args, **kwargs): 9090 # self.dispatch 9191 print(request.user) 9292 print(request.auth) 9393 return Response('GET请求,响应内容') 9494 9595 def post(self, request, *args, **kwargs): 9696 return Response('POST请求,响应内容') 9797 9898 def put(self, request, *args, **kwargs): 9999 return Response('PUT请求,响应内容')
views.py

1 1 # 2 2 class MyAuthtication(BasicAuthentication): 3 3 def authenticate(self, request): 4 4 token = request.query_params.get('token') #注意是没有GET的,用query_params表示 5 5 if token == 'zxxzzxzc': 6 6 return ('uuuuuu','afsdsgdf') #返回user,auth 7 7 # raise AuthenticationFailed('认证错误') #只要抛出认证错误这样的异常就会去执行下面的函数 8 8 raise APIException('认证错误') 9 9 def authenticate_header(self, request): #认证不成功的时候执行 1010 return 'Basic reala="api"' 1111 1212 class UserView(APIView): 1313 authentication_classes = [MyAuthtication,] 1414 def get(self,request,*args,**kwargs): 1515 print(request.user) 1616 print(request.auth) 1717 return Response('用户列表')
自定义认证功能

二、权限
1、需求:Host是匿名用户和用户都能访问 #匿名用户的request.user = none;User只有注册用户能访问

11 from app03 import views 22 from django.conf.urls import url 33 urlpatterns = [ 44 # django rest framework 55 url('^auth/', views.AuthView.as_view()), 66 url(r'^hosts/', views.HostView.as_view()), 77 url(r'^users/', views.UsersView.as_view()), 88 url(r'^salary/', views.SalaryView.as_view()), 99 ]
urls.py

1 1 from django.shortcuts import render 2 2 from rest_framework.views import APIView #继承的view 3 3 from rest_framework.response import Response #友好的返回 4 4 from rest_framework.authentication import BaseAuthentication #认证的类 5 5 from rest_framework.authentication import BasicAuthentication 6 6 from app01 import models 7 7 from rest_framework import exceptions 8 8 from rest_framework.permissions import AllowAny #权限在这个类里面 9 9 from rest_framework.throttling import BaseThrottle,SimpleRateThrottle 1010 # Create your views here. 1111 # +++++++++++++++认证类和权限类======================== 1212 class MyAuthentication(BaseAuthentication): 1313 def authenticate(self, request): 1414 token = request.query_params.get('token') 1515 obj = models.UserInfo.objects.filter(token=token).first() 1616 if obj : #如果认证成功,返回用户名和auth 1717 return (obj.username,obj) 1818 return None #如果没有认证成功就不处理,进行下一步 1919 2020 def authenticate_header(self, request): 2121 pass 2222 2323 class MyPermission(object): 2424 message = '无权访问' 2525 def has_permission(self,request,view): #has_permission里面的self是view视图对象 2626 if request.user: 2727 return True #如果不是匿名用户就说明有权限 2828 return False #否则无权限 2929 3030 class AdminPermission(object): 3131 message = '无权访问' 3232 def has_permission(self, request, view): # has_permission里面的self是view视图对象 3333 if request.user=='haiyun': 3434 return True # 返回True表示有权限 3535 return False #返回False表示无权限 3636 3737 # +++++++++++++++++++++++++++ 3838 class AuthView(APIView): 3939 authentication_classes = [] #认证页面不需要认证 4040 4141 def get(self,request): 4242 self.dispatch 4343 return '认证列表' 4444 4545 class HostView(APIView): 4646 '''需求: 4747 Host是匿名用户和用户都能访问 #匿名用户的request.user = none 4848 User只有注册用户能访问 4949 ''' 5050 authentication_classes = [MyAuthentication,] 5151 permission_classes = [] #都能访问就没必要设置权限了 5252 def get(self,request): 5353 print(request.user) 5454 print(request.auth) 5555 return Response('主机列表') 5656 5757 class UsersView(APIView): 5858 '''用户能访问,request.user里面有值''' 5959 authentication_classes = [MyAuthentication,] 6060 permission_classes = [MyPermission,] 6161 def get(self,request): 6262 print(request.user,'111111111') 6363 return Response('用户列表') 6464 6565 def permission_denied(self, request, message=None): 6666 """ 6767 If request is not permitted, determine what kind of exception to raise. 6868 """ 6969 if request.authenticators and not request.successful_authenticator: 7070 '''如果没有通过认证,并且权限中return False了,就会报下面的这个异常了''' 7171 raise exceptions.NotAuthenticated(detail='无权访问') 7272 raise exceptions.PermissionDenied(detail=message)
views.py

1 1 class SalaryView(APIView): 2 2 '''用户能访问''' 3 3 message ='无权访问' 4 4 authentication_classes = [MyAuthentication,] #验证是不是用户 5 5 permission_classes = [MyPermission,AdminPermission,] #再看用户有没有权限,如果有权限在判断有没有管理员的权限 6 6 def get(self,request): 7 7 return Response('薪资列表') 8 8 9 9 def permission_denied(self, request, message=None): 1010 """ 1111 If request is not permitted, determine what kind of exception to raise. 1212 """ 1313 if request.authenticators and not request.successful_authenticator: 1414 '''如果没有通过认证,并且权限中return False了,就会报下面的这个异常了''' 1515 raise exceptions.NotAuthenticated(detail='无权访问') 1616 raise exceptions.PermissionDenied(detail=message)
认证和权限配合使用
如果遇上这样的,还可以自定制,参考源码

1def check_permissions(self, request): 2 """ 3 Check if the request should be permitted. 4 Raises an appropriate exception if the request is not permitted. 5 """ 6 for permission in self.get_permissions(): 7 #循环每一个permission对象,调用has_permission 8 #如果False,则抛出异常 9 #True 说明有权访问 10 if not permission.has_permission(request, self): 11 self.permission_denied( 12 request, message=getattr(permission, 'message', None) 13 ) 14 15def permission_denied(self, request, message=None): 16 """ 17 If request is not permitted, determine what kind of exception to raise. 18 """ 19 if request.authenticators and not request.successful_authenticator: 20 '''如果没有通过认证,并且权限中return False了,就会报下面的这个异常了''' 21 raise exceptions.NotAuthenticated() 22 raise exceptions.PermissionDenied(detail=message)
那么我们可以重写permission_denied这个方法,如下:

1 1 class UsersView(APIView): 2 2 '''用户能访问,request.user里面有值''' 3 3 authentication_classes = [MyAuthentication,] 4 4 permission_classes = [MyPermission,] 5 5 def get(self,request): 6 6 return Response('用户列表') 7 7 8 8 def permission_denied(self, request, message=None): 9 9 """ 1010 If request is not permitted, determine what kind of exception to raise. 1111 """ 1212 if request.authenticators and not request.successful_authenticator: 1313 '''如果没有通过认证,并且权限中return False了,就会报下面的这个异常了''' 1414 raise exceptions.NotAuthenticated(detail='无权访问') 1515 raise exceptions.PermissionDenied(detail=message)
views.py

2. 全局使用
上述操作中均是对单独视图进行特殊配置,如果想要对全局进行配置,则需要再配置文件中写入即可。

1 1 REST_FRAMEWORK = { 2 2 'UNAUTHENTICATED_USER': None, 3 3 'UNAUTHENTICATED_TOKEN': None, #将匿名用户设置为None 4 4 "DEFAULT_AUTHENTICATION_CLASSES": [ 5 5 "app01.utils.MyAuthentication", 6 6 ], 7 7 'DEFAULT_PERMISSION_CLASSES':[ 8 8 "app03.utils.MyPermission",#设置路径, 9 9 ] 1010 }
settings.py

1 1 class AuthView(APIView): 2 2 authentication_classes = [] #认证页面不需要认证 3 3 4 4 def get(self,request): 5 5 self.dispatch 6 6 return '认证列表' 7 7 8 8 class HostView(APIView): 9 9 '''需求: 1010 Host是匿名用户和用户都能访问 #匿名用户的request.user = none 1111 User只有注册用户能访问 1212 ''' 1313 authentication_classes = [MyAuthentication,] 1414 permission_classes = [] #都能访问就没必要设置权限了 1515 def get(self,request): 1616 print(request.user) 1717 print(request.auth) 1818 return Response('主机列表') 1919 2020 class UsersView(APIView): 2121 '''用户能访问,request.user里面有值''' 2222 authentication_classes = [MyAuthentication,] 2323 permission_classes = [MyPermission,] 2424 def get(self,request): 2525 print(request.user,'111111111') 2626 return Response('用户列表') 2727 2828 def permission_denied(self, request, message=None): 2929 """ 3030 If request is not permitted, determine what kind of exception to raise. 3131 """ 3232 if request.authenticators and not request.successful_authenticator: 3333 '''如果没有通过认证,并且权限中return False了,就会报下面的这个异常了''' 3434 raise exceptions.NotAuthenticated(detail='无权访问') 3535 raise exceptions.PermissionDenied(detail=message) 3636 3737 3838 class SalaryView(APIView): 3939 '''用户能访问''' 4040 message ='无权访问' 4141 authentication_classes = [MyAuthentication,] #验证是不是用户 4242 permission_classes = [MyPermission,AdminPermission,] #再看用户有没有权限,如果有权限在判断有没有管理员的权限 4343 def get(self,request): 4444 return Response('薪资列表') 4545 4646 def permission_denied(self, request, message=None): 4747 """ 4848 If request is not permitted, determine what kind of exception to raise. 4949 """ 5050 if request.authenticators and not request.successful_authenticator: 5151 '''如果没有通过认证,并且权限中return False了,就会报下面的这个异常了''' 5252 raise exceptions.NotAuthenticated(detail='无权访问') 5353 raise exceptions.PermissionDenied(detail=message)
Views.py
三、限流
1、为什么要限流呢?
答:防爬
2、限制访问频率源码分析

1 self.check_throttles(request)
self.check_throttles(request)

1 1 def check_throttles(self, request): 2 2 """ 3 3 Check if request should be throttled. 4 4 Raises an appropriate exception if the request is throttled. 5 5 """ 6 6 for throttle in self.get_throttles(): 7 7 #循环每一个throttle对象,执行allow_request方法 8 8 # allow_request: 9 9 #返回False,说明限制访问频率 1010 #返回True,说明不限制,通行 1111 if not throttle.allow_request(request, self): 1212 self.throttled(request, throttle.wait()) 1313 #throttle.wait()表示还要等多少秒就能访问了
check_throttles

11 def get_throttles(self): 22 """ 33 Instantiates and returns the list of throttles that this view uses. 44 """ 55 #返回对象 66 return [throttle() for throttle in self.throttle_classes]
get_throttles

1 throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
找到类,可自定制类throttle_classes

1 1 class BaseThrottle(object): 2 2 """ 3 3 Rate throttling of requests. 4 4 """ 5 5 6 6 def allow_request(self, request, view): 7 7 """ 8 8 Return `True` if the request should be allowed, `False` otherwise. 9 9 """ 1010 raise NotImplementedError('.allow_request() must be overridden') 1111 1212 def get_ident(self, request): 1313 """ 1414 Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR 1515 if present and number of proxies is > 0. If not use all of 1616 HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. 1717 """ 1818 xff = request.META.get('HTTP_X_FORWARDED_FOR') 1919 remote_addr = request.META.get('REMOTE_ADDR') 2020 num_proxies = api_settings.NUM_PROXIES 2121 2222 if num_proxies is not None: 2323 if num_proxies == 0 or xff is None: 2424 return remote_addr 2525 addrs = xff.split(',') 2626 client_addr = addrs[-min(num_proxies, len(addrs))] 2727 return client_addr.strip() 2828 2929 return ''.join(xff.split()) if xff else remote_addr 3030 3131 def wait(self): 3232 """ 3333 Optionally, return a recommended number of seconds to wait before 3434 the next request. 3535 """ 3636 return None
BaseThrottle

1 zz
也可以重写allow_request方法

11 def throttled(self, request, wait): 22 """ 33 If request is throttled, determine what kind of exception to raise. 44 """ 55 raise exceptions.Throttled(wait)
可自定制返回的错误信息throttled

1 1 class Throttled(APIException): 2 2 status_code = status.HTTP_429_TOO_MANY_REQUESTS 3 3 default_detail = _('Request was throttled.') 4 4 extra_detail_singular = 'Expected available in {wait} second.' 5 5 extra_detail_plural = 'Expected available in {wait} seconds.' 6 6 default_code = 'throttled' 7 7 8 8 def __init__(self, wait=None, detail=None, code=None): 9 9 if detail is None: 1010 detail = force_text(self.default_detail) 1111 if wait is not None: 1212 wait = math.ceil(wait) 1313 detail = ' '.join(( 1414 detail, 1515 force_text(ungettext(self.extra_detail_singular.format(wait=wait), 1616 self.extra_detail_plural.format(wait=wait), 1717 wait)))) 1818 self.wait = wait 1919 super(Throttled, self).__init__(detail, code)
raise exceptions.Throttled(wait)错误信息详情
下面来看看最简单的从源码中分析的示例,这只是举例说明了一下

11 from django.conf.urls import url 22 from app04 import views 33 urlpatterns = [ 44 url('limit/',views.LimitView.as_view()), 55 66 ]
urls.py

1 1 from django.shortcuts import render 2 2 from rest_framework.views import APIView 3 3 from rest_framework.response import Response 4 4 from rest_framework import exceptions 5 5 # from rest_framewor import 6 6 # Create your views here. 7 7 class MyThrottle(object): 8 8 def allow_request(self,request,view): 9 9 #返回False,限制 1010 #返回True,不限制 1111 pass 1212 def wait(self): 1313 return 1000 1414 1515 1616 class LimitView(APIView): 1717 authentication_classes = [] #不让认证用户 1818 permission_classes = [] #不让验证权限 1919 throttle_classes = [MyThrottle, ] 2020 def get(self,request): 2121 # self.dispatch 2222 return Response('控制访问频率示例') 2323 2424 def throttled(self, request, wait): 2525 '''可定制方法设置中文错误''' 2626 # raise exceptions.Throttled(wait) 2727 class MyThrottle(exceptions.Throttled): 2828 default_detail = '请求被限制' 2929 extra_detail_singular = 'Expected available in {wait} second.' 3030 extra_detail_plural = 'Expected available in {wait} seconds.' 3131 default_code = '还需要再等{wait}秒' 3232 raise MyThrottle(wait)
views.py
3、需求:对匿名用户进行限制,每个用户一分钟允许访问10次(只针对用户来说)
a、基于用户IP限制访问频率
流程分析:
- 先获取用户信息,如果是匿名用户,获取IP。如果不是匿名用户就可以获取用户名。
- 获取匿名用户IP,在request里面获取,比如IP= 1.1.1.1。
- 吧获取到的IP添加到到recode字典里面,需要在添加之前先限制一下。
- 如果时间间隔大于60秒,说明时间久远了,就把那个时间给剔除 了pop。在timelist列表里面现在留的是有效的访问时间段。
- 然后判断他的访问次数超过了10次没有,如果超过了时间就return False。
- 美中不足的是时间是固定的,我们改变他为动态的:列表里面最开始进来的时间和当前的时间进行比较,看需要等多久。
具体实现:

1 1 from django.shortcuts import render 2 2 from rest_framework.views import APIView 3 3 from rest_framework.response import Response 4 4 from rest_framework import exceptions 5 5 from rest_framework.throttling import BaseThrottle,SimpleRateThrottle #限制访问频率 6 6 import time 7 7 # Create your views here. 8 8 RECORD = {} 9 9 class MyThrottle(BaseThrottle): 1010 1111 def allow_request(self,request,view): 1212 '''对匿名用户进行限制,每个用户一分钟访问10次 ''' 1313 ctime = time.time() 1414 ip = '1.1.1.1' 1515 if ip not in RECORD: 1616 RECORD[ip] = [ctime] 1717 else: 1818 #[152042123,15204212,3152042,123152042123] 1919 time_list = RECORD[ip] #获取ip里面的值 2020 while True: 2121 val = time_list[-1]#取出最后一个时间,也就是访问最早的时间 2222 if (ctime-60)>val: #吧时间大于60秒的给剔除了 2323 time_list.pop() 2424 #剔除了之后timelist里面就是有效的时间了,在进行判断他的访问次数是不是超过10次 2525 else: 2626 break 2727 if len(time_list) >10: 2828 return False # 返回False,限制 2929 time_list.insert(0, ctime) 3030 return True #返回True,不限制 3131 3232 def wait(self): 3333 ctime = time.time() 3434 first_in_time = RECORD['1.1.1.1'][-1] 3535 wt = 60-(ctime-first_in_time) 3636 return wt 3737 3838 3939 class LimitView(APIView): 4040 authentication_classes = [] #不让认证用户 4141 permission_classes = [] #不让验证权限 4242 throttle_classes = [MyThrottle, ] 4343 def get(self,request): 4444 # self.dispatch 4545 return Response('控制访问频率示例') 4646 4747 def throttled(self, request, wait): 4848 '''可定制方法设置中文错误''' 4949 # raise exceptions.Throttled(wait) 5050 class MyThrottle(exceptions.Throttled): 5151 default_detail = '请求被限制' 5252 extra_detail_singular = 'Expected available in {wait} second.' 5353 extra_detail_plural = 'Expected available in {wait} seconds.' 5454 default_code = '还需要再等{wait}秒' 5555 raise MyThrottle(wait)
views初级版本

1 1 # from django.shortcuts import render 2 2 # from rest_framework.views import APIView 3 3 # from rest_framework.response import Response 4 4 # from rest_framework import exceptions 5 5 # from rest_framework.throttling import BaseThrottle,SimpleRateThrottle #限制访问频率 6 6 # import time 7 7 # # Create your views here. 8 8 # RECORD = {} 9 9 # class MyThrottle(BaseThrottle): 10 10 # 11 11 # def allow_request(self,request,view): 12 12 # '''对匿名用户进行限制,每个用户一分钟访问10次 ''' 13 13 # ctime = time.time() 14 14 # ip = '1.1.1.1' 15 15 # if ip not in RECORD: 16 16 # RECORD[ip] = [ctime] 17 17 # else: 18 18 # #[152042123,15204212,3152042,123152042123] 19 19 # time_list = RECORD[ip] #获取ip里面的值 20 20 # while True: 21 21 # val = time_list[-1]#取出最后一个时间,也就是访问最早的时间 22 22 # if (ctime-60)>val: #吧时间大于60秒的给剔除了 23 23 # time_list.pop() 24 24 # #剔除了之后timelist里面就是有效的时间了,在进行判断他的访问次数是不是超过10次 25 25 # else: 26 26 # break 27 27 # if len(time_list) >10: 28 28 # return False # 返回False,限制 29 29 # time_list.insert(0, ctime) 30 30 # return True #返回True,不限制 31 31 # 32 32 # def wait(self): 33 33 # ctime = time.time() 34 34 # first_in_time = RECORD['1.1.1.1'][-1] 35 35 # wt = 60-(ctime-first_in_time) 36 36 # return wt 37 37 # 38 38 # 39 39 # class LimitView(APIView): 40 40 # authentication_classes = [] #不让认证用户 41 41 # permission_classes = [] #不让验证权限 42 42 # throttle_classes = [MyThrottle, ] 43 43 # def get(self,request): 44 44 # # self.dispatch 45 45 # return Response('控制访问频率示例') 46 46 # 47 47 # def throttled(self, request, wait): 48 48 # '''可定制方法设置中文错误''' 49 49 # # raise exceptions.Throttled(wait) 50 50 # class MyThrottle(exceptions.Throttled): 51 51 # default_detail = '请求被限制' 52 52 # extra_detail_singular = 'Expected available in {wait} second.' 53 53 # extra_detail_plural = 'Expected available in {wait} seconds.' 54 54 # default_code = '还需要再等{wait}秒' 55 55 # raise MyThrottle(wait) 56 56 57 57 58 58 59 59 from django.shortcuts import render 60 60 from rest_framework.views import APIView 61 61 from rest_framework.response import Response 62 62 from rest_framework import exceptions 63 63 from rest_framework.throttling import BaseThrottle,SimpleRateThrottle #限制访问频率 64 64 import time 65 65 # Create your views here. 66 66 RECORD = {} 67 67 class MyThrottle(BaseThrottle): 68 68 69 69 def allow_request(self,request,view): 70 70 '''对匿名用户进行限制,每个用户一分钟访问10次 ''' 71 71 ctime = time.time() 72 72 self.ip =self.get_ident(request) 73 73 if self.ip not in RECORD: 74 74 RECORD[self.ip] = [ctime] 75 75 else: 76 76 #[152042123,15204212,3152042,123152042123] 77 77 time_list = RECORD[self.ip] #获取ip里面的值 78 78 while True: 79 79 val = time_list[-1]#取出最后一个时间,也就是访问最早的时间 80 80 if (ctime-60)>val: #吧时间大于60秒的给剔除了 81 81 time_list.pop() 82 82 #剔除了之后timelist里面就是有效的时间了,在进行判断他的访问次数是不是超过10次 83 83 else: 84 84 break 85 85 if len(time_list) >10: 86 86 return False # 返回False,限制 87 87 time_list.insert(0, ctime) 88 88 return True #返回True,不限制 89 89 90 90 def wait(self): 91 91 ctime = time.time() 92 92 first_in_time = RECORD[self.ip][-1] 93 93 wt = 60-(ctime-first_in_time) 94 94 return wt 95 95 96 96 97 97 class LimitView(APIView): 98 98 authentication_classes = [] #不让认证用户 99 99 permission_classes = [] #不让验证权限 100100 throttle_classes = [MyThrottle, ] 101101 def get(self,request): 102102 # self.dispatch 103103 return Response('控制访问频率示例') 104104 105105 def throttled(self, request, wait): 106106 '''可定制方法设置中文错误''' 107107 # raise exceptions.Throttled(wait) 108108 class MyThrottle(exceptions.Throttled): 109109 default_detail = '请求被限制' 110110 extra_detail_singular = 'Expected available in {wait} second.' 111111 extra_detail_plural = 'Expected available in {wait} seconds.' 112112 default_code = '还需要再等{wait}秒' 113113 raise MyThrottle(wait)
稍微做了改动

b、用resetframework内部的限制访问频率(利于Django缓存)
源码分析:
from rest_framework.throttling import BaseThrottle,SimpleRateThrottle #限制访问频率

1 1 class BaseThrottle(object): 2 2 """ 3 3 Rate throttling of requests. 4 4 """ 5 5 6 6 def allow_request(self, request, view): 7 7 """ 8 8 Return `True` if the request should be allowed, `False` otherwise. 9 9 """ 1010 raise NotImplementedError('.allow_request() must be overridden') 1111 1212 def get_ident(self, request): #唯一标识 1313 """ 1414 Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR 1515 if present and number of proxies is > 0. If not use all of 1616 HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. 1717 """ 1818 xff = request.META.get('HTTP_X_FORWARDED_FOR') 1919 remote_addr = request.META.get('REMOTE_ADDR') #获取IP等 2020 num_proxies = api_settings.NUM_PROXIES 2121 2222 if num_proxies is not None: 2323 if num_proxies == 0 or xff is None: 2424 return remote_addr 2525 addrs = xff.split(',') 2626 client_addr = addrs[-min(num_proxies, len(addrs))] 2727 return client_addr.strip() 2828 2929 return ''.join(xff.split()) if xff else remote_addr 3030 3131 def wait(self): 3232 """ 3333 Optionally, return a recommended number of seconds to wait before 3434 the next request. 3535 """ 3636 return None
BaseThrottle相当于一个抽象类

1 1 class SimpleRateThrottle(BaseThrottle): 2 2 """ 3 3 一个简单的缓存实现,只需要` get_cache_key() `。被覆盖。 4 4 速率(请求/秒)是由视图上的“速率”属性设置的。类。该属性是一个字符串的形式number_of_requests /期。 5 5 周期应该是:(的),“秒”,“M”,“min”,“h”,“小时”,“D”,“一天”。 6 6 以前用于节流的请求信息存储在高速缓存中。 7 7 A simple cache implementation, that only requires `.get_cache_key()` 8 8 to be overridden. 9 9 10 10 The rate (requests / seconds) is set by a `rate` attribute on the View 11 11 class. The attribute is a string of the form 'number_of_requests/period'. 12 12 13 13 Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day') 14 14 15 15 Previous request information used for throttling is stored in the cache. 16 16 """ 17 17 cache = default_cache 18 18 timer = time.time 19 19 cache_format = 'throttle_%(scope)s_%(ident)s' 20 20 scope = None 21 21 THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES 22 22 23 23 def __init__(self): 24 24 if not getattr(self, 'rate', None): 25 25 self.rate = self.get_rate() 26 26 self.num_requests, self.duration = self.parse_rate(self.rate) 27 27 28 28 def get_cache_key(self, request, view):#这个相当于是一个半成品,我们可以来补充它 29 29 """ 30 30 Should return a unique cache-key which can be used for throttling. 31 31 Must be overridden. 32 32 33 33 May return `None` if the request should not be throttled. 34 34 """ 35 35 raise NotImplementedError('.get_cache_key() must be overridden') 36 36 37 37 def get_rate(self): 38 38 """ 39 39 Determine the string representation of the allowed request rate. 40 40 """ 41 41 if not getattr(self, 'scope', None): 42 42 msg = ("You must set either `.scope` or `.rate` for '%s' throttle" % 43 43 self.__class__.__name__) 44 44 raise ImproperlyConfigured(msg) 45 45 46 46 try: 47 47 return self.THROTTLE_RATES[self.scope] 48 48 except KeyError: 49 49 msg = "No default throttle rate set for '%s' scope" % self.scope 50 50 raise ImproperlyConfigured(msg) 51 51 52 52 def parse_rate(self, rate): 53 53 """ 54 54 Given the request rate string, return a two tuple of: 55 55 <allowed number of requests>, <period of time in seconds> 56 56 """ 57 57 if rate is None: 58 58 return (None, None) 59 59 num, period = rate.split('/') 60 60 num_requests = int(num) 61 61 duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]] 62 62 return (num_requests, duration) 63 63 64 64 #1、一进来会先执行他, 65 65 def allow_request(self, request, view): 66 66 """ 67 67 Implement the check to see if the request should be throttled. 68 68 69 69 On success calls `throttle_success`. 70 70 On failure calls `throttle_failure`. 71 71 """ 72 72 if self.rate is None: 73 73 return True 74 74 75 75 self.key = self.get_cache_key(request, view) #2、执行get_cache_key,这里的self.key就相当于我们举例ip 76 76 if self.key is None: 77 77 return True 78 78 79 79 self.history = self.cache.get(self.key, []) #3、得到的key,默认是一个列表,赋值给了self.history, 80 80 # 这时候self.history就是每一个ip对应的访问记录 81 81 self.now = self.timer() 82 82 83 83 # Drop any requests from the history which have now passed the 84 84 # throttle duration 85 85 while self.history and self.history[-1] <= self.now - self.duration: 86 86 self.history.pop() 87 87 if len(self.history) >= self.num_requests: 88 88 return self.throttle_failure() 89 89 return self.throttle_success() 90 90 91 91 def throttle_success(self): 92 92 """ 93 93 Inserts the current request's timestamp along with the key 94 94 into the cache. 95 95 """ 96 96 self.history.insert(0, self.now) 97 97 self.cache.set(self.key, self.history, self.duration) 98 98 return True 99 99 100100 def throttle_failure(self): 101101 """ 102102 Called when a request to the API has failed due to throttling. 103103 """ 104104 return False 105105 106106 def wait(self): 107107 """ 108108 Returns the recommended next request time in seconds. 109109 """ 110110 if self.history: 111111 remaining_duration = self.duration - (self.now - self.history[-1]) 112112 else: 113113 remaining_duration = self.duration 114114 115115 available_requests = self.num_requests - len(self.history) + 1 116116 if available_requests <= 0: 117117 return None 118118 119119 return remaining_duration / float(available_requests)
SimpleRateThrottle
请求一进来会先执行SimpleRateThrottle这个类的构造方法

11 def __init__(self): 22 if not getattr(self, 'rate', None): 33 self.rate = self.get_rate() #点进去看到需要些一个scope ,2/m 44 self.num_requests, self.duration = self.parse_rate(self.rate)
__init__

1 1 def get_rate(self): 2 2 """ 3 3 Determine the string representation of the allowed request rate. 4 4 """ 5 5 if not getattr(self, 'scope', None): #检测必须有scope,没有就报错了 6 6 msg = ("You must set either `.scope` or `.rate` for '%s' throttle" % 7 7 self.__class__.__name__) 8 8 raise ImproperlyConfigured(msg) 9 9 1010 try: 1111 return self.THROTTLE_RATES[self.scope] 1212 except KeyError: 1313 msg = "No default throttle rate set for '%s' scope" % self.scope 1414 raise ImproperlyConfigured(msg)
get_rate

1 1 def parse_rate(self, rate): 2 2 """ 3 3 Given the request rate string, return a two tuple of: 4 4 <allowed number of requests>, <period of time in seconds> 5 5 """ 6 6 if rate is None: 7 7 return (None, None) 8 8 num, period = rate.split('/') 9 9 num_requests = int(num) 1010 duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]] 1111 return (num_requests, duration)
parse_rate

1 1 #2、接下来会先执行他, 2 2 def allow_request(self, request, view): 3 3 """ 4 4 Implement the check to see if the request should be throttled. 5 5 6 6 On success calls `throttle_success`. 7 7 On failure calls `throttle_failure`. 8 8 """ 9 9 if self.rate is None: 1010 return True 1111 1212 self.key = self.get_cache_key(request, view) #2、执行get_cache_key,这里的self.key就相当于我们举例ip 1313 if self.key is None: 1414 return True #不限制 1515 # [114521212,11452121211,45212121145,21212114,521212] 1616 self.history = self.cache.get(self.key, []) #3、得到的key,默认是一个列表,赋值给了self.history, 1717 # 这时候self.history就是每一个ip对应的访问记录 1818 self.now = self.timer() 1919 2020 # Drop any requests from the history which have now passed the 2121 # throttle duration 2222 while self.history and self.history[-1] <= self.now - self.duration: 2323 self.history.pop() 2424 if len(self.history) >= self.num_requests: 2525 return self.throttle_failure() 2626 return self.throttle_success()
allow_request

1 1 def wait(self): 2 2 """ 3 3 Returns the recommended next request time in seconds. 4 4 """ 5 5 if self.history: 6 6 remaining_duration = self.duration - (self.now - self.history[-1]) 7 7 else: 8 8 remaining_duration = self.duration 9 9 1010 available_requests = self.num_requests - len(self.history) + 1 1111 if available_requests <= 0: 1212 return None 1313 1414 return remaining_duration / float(available_requests)
wait
代码实现:

1 1 ###########用resetframework内部的限制访问频率############## 2 2 class MySimpleRateThrottle(SimpleRateThrottle): 3 3 scope = 'xxx' 4 4 def get_cache_key(self, request, view): 5 5 return self.get_ident(request) #返回唯一标识IP 6 6 7 7 class LimitView(APIView): 8 8 authentication_classes = [] #不让认证用户 9 9 permission_classes = [] #不让验证权限 1010 throttle_classes = [MySimpleRateThrottle, ] 1111 def get(self,request): 1212 # self.dispatch 1313 return Response('控制访问频率示例') 1414 1515 def throttled(self, request, wait): 1616 '''可定制方法设置中文错误''' 1717 # raise exceptions.Throttled(wait) 1818 class MyThrottle(exceptions.Throttled): 1919 default_detail = '请求被限制' 2020 extra_detail_singular = 'Expected available in {wait} second.' 2121 extra_detail_plural = 'Expected available in {wait} seconds.' 2222 default_code = '还需要再等{wait}秒' 2323 raise MyThrottle(wait)
views.py
记得在settings里面配置

1 1 REST_FRAMEWORK = { 2 2 'UNAUTHENTICATED_USER': None, 3 3 'UNAUTHENTICATED_TOKEN': None, #将匿名用户设置为None 4 4 "DEFAULT_AUTHENTICATION_CLASSES": [ 5 5 "app01.utils.MyAuthentication", 6 6 ], 7 7 'DEFAULT_PERMISSION_CLASSES':[ 8 8 # "app03.utils.MyPermission",#设置路径, 9 9 ], 1010 'DEFAULT_THROTTLE_RATES':{ 1111 'xxx':'2/minute' #2分钟 1212 } 1313 } 1414 1515 #缓存:放在文件 1616 CACHES = { 1717 'default': { 1818 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 1919 'LOCATION': 'cache', #文件路径 2020 } 2121 }
settings.py
4、对匿名用户进行限制,每个用户1分钟允许访问5次,对于登录的普通用户1分钟访问10次,VIP用户一分钟访问20次
- 比如首页可以匿名访问
- #先认证,只有认证了才知道是不是匿名的,
- #权限登录成功之后才能访问, ,index页面就不需要权限了
- If request.user #判断登录了没有

11 from django.contrib import admin 22 33 from django.conf.urls import url, include 44 from app05 import views 55 66 urlpatterns = [ 77 url('index/',views.IndexView.as_view()), 88 url('manage/',views.ManageView.as_view()), 99 ]
urls.py

1 1 from django.shortcuts import render 2 2 from rest_framework.views import APIView 3 3 from rest_framework.response import Response 4 4 from rest_framework.authentication import BaseAuthentication #认证需要 5 5 from rest_framework.throttling import BaseThrottle,SimpleRateThrottle #限流处理 6 6 from rest_framework.permissions import BasePermission 7 7 from rest_framework import exceptions 8 8 from app01 import models 9 9 # Create your views here. 1010 ###############3##认证##################### 1111 class MyAuthentcate(BaseAuthentication): 1212 '''检查用户是否存在,如果存在就返回user和auth,如果没有就返回''' 1313 def authenticate(self, request): 1414 token = request.query_params.get('token') 1515 obj = models.UserInfo.objects.filter(token=token).first() 1616 if obj: 1717 return (obj.username,obj.token) 1818 return None #表示我不处理 1919 2020 ##################权限##################### 2121 class MyPermission(BasePermission): 2222 message='无权访问' 2323 def has_permission(self, request, view): 2424 if request.user: 2525 return True #true表示有权限 2626 return False #false表示无权限 2727 2828 class AdminPermission(BasePermission): 2929 message = '无权访问' 3030 3131 def has_permission(self, request, view): 3232 if request.user=='haiyan': 3333 return True # true表示有权限 3434 return False # false表示无权限 3535 3636 ############3#####限流##################3## 3737 class AnonThrottle(SimpleRateThrottle): 3838 scope = 'wdp_anon' #相当于设置了最大的访问次数和时间 3939 def get_cache_key(self, request, view): 4040 if request.user: 4141 return None #返回None表示我不限制,登录用户我不管 4242 #匿名用户 4343 return self.get_ident(request) #返回一个唯一标识IP 4444 4545 class UserThrottle(SimpleRateThrottle): 4646 scope = 'wdp_user' 4747 def get_cache_key(self, request, view): 4848 #登录用户 4949 if request.user: 5050 return request.user 5151 return None #返回NOne表示匿名用户我不管 5252 5353 5454 ##################视图##################### 5555 #首页支持匿名访问, 5656 #无需要登录就可以访问 5757 class IndexView(APIView): 5858 authentication_classes = [MyAuthentcate,] #认证判断他是不是匿名用户 5959 permission_classes = [] #一般主页就不需要权限验证了 6060 throttle_classes = [AnonThrottle,UserThrottle,] #对匿名用户和普通用户的访问限制 6161 6262 def get(self,request): 6363 # self.dispatch 6464 return Response('访问首页') 6565 6666 def throttled(self, request, wait): 6767 '''可定制方法设置中文错误''' 6868 6969 # raise exceptions.Throttled(wait) 7070 class MyThrottle(exceptions.Throttled): 7171 default_detail = '请求被限制' 7272 extra_detail_singular = 'Expected available in {wait} second.' 7373 extra_detail_plural = 'Expected available in {wait} seconds.' 7474 default_code = '还需要再等{wait}秒' 7575 7676 raise MyThrottle(wait) 7777 7878 #需登录就可以访问 7979 class ManageView(APIView): 8080 authentication_classes = [MyAuthentcate, ] # 认证判断他是不是匿名用户 8181 permission_classes = [MyPermission,] # 一般主页就不需要权限验证了 8282 throttle_classes = [AnonThrottle, UserThrottle, ] # 对匿名用户和普通用户的访问限制 8383 8484 def get(self, request): 8585 # self.dispatch 8686 return Response('管理人员访问页面') 8787 8888 def throttled(self, request, wait): 8989 '''可定制方法设置中文错误''' 9090 9191 # raise exceptions.Throttled(wait) 9292 class MyThrottle(exceptions.Throttled): 9393 default_detail = '请求被限制' 9494 extra_detail_singular = 'Expected available in {wait} second.' 9595 extra_detail_plural = 'Expected available in {wait} seconds.' 9696 default_code = '还需要再等{wait}秒' 9797 9898 raise MyThrottle(wait)
views.py
四、总结
1、认证:就是检查用户是否存在;如果存在返回(request.user,request.auth);不存在request.user/request.auth=None
2、权限:进行职责的划分
3、限制访问频率
1认证 2 - 类:authenticate/authenticate_header ##验证不成功的时候执行的 3 - 返回值: 4 - return None, 5 - return (user,auth), 6 - raise 异常 7 - 配置: 8 - 视图: 9 class IndexView(APIView): 10 authentication_classes = [MyAuthentication,] 11 - 全局: 12 REST_FRAMEWORK = { 13 'UNAUTHENTICATED_USER': None, 14 'UNAUTHENTICATED_TOKEN': None, 15 "DEFAULT_AUTHENTICATION_CLASSES": [ 16 # "app02.utils.MyAuthentication", 17 ], 18 } 19 20权限 21 - 类:has_permission/has_object_permission 22 - 返回值: 23 - True、#有权限 24 - False、#无权限 25 - exceptions.PermissionDenied(detail="错误信息") #异常自己随意,想抛就抛,错误信息自己指定 26 - 配置: 27 - 视图: 28 class IndexView(APIView): 29 permission_classes = [MyPermission,] 30 - 全局: 31 REST_FRAMEWORK = { 32 "DEFAULT_PERMISSION_CLASSES": [ 33 # "app02.utils.MyAuthentication", 34 ], 35 } 36限流 37 - 类:allow_request/wait PS: scope = "wdp_user" 38 - 返回值: return True、#不限制 return False #限制 39 - 配置: 40 - 视图: 41 class IndexView(APIView): 42 43 throttle_classes=[AnonThrottle,UserThrottle,] 44 def get(self,request,*args,**kwargs): 45 self.dispatch 46 return Response('访问首页') 47 - 全局 48 REST_FRAMEWORK = { 49 "DEFAULT_THROTTLE_CLASSES":[ 50 51 ], 52 'DEFAULT_THROTTLE_RATES':{ 53 'wdp_anon':'5/minute', 54 'wdp_user':'10/minute', 55 } 56 }