REST framwork之认证,权限与频率
认证组件
局部视图认证
在app01.service.auth.py:
class Authentication(BaseAuthentication): def authenticate(self,request): token=request._request.GET.get("token") token_obj=UserToken.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed("验证失败!") return (token_obj.user,token_obj)
在views.py:
def get_random_str(user): import hashlib,time ctime=str(time.time()) md5=hashlib.md5(bytes(user,encoding="utf8")) md5.update(bytes(ctime,encoding="utf8")) return md5.hexdigest() from app01.service.auth import * from django.http import JsonResponse class LoginViewSet(APIView): authentication_classes = [Authentication,] def post(self,request,*args,**kwargs): res={"code":1000,"msg":None} try: user=request._request.POST.get("user") pwd=request._request.POST.get("pwd") user_obj=UserInfo.objects.filter(user=user,pwd=pwd).first() print(user,pwd,user_obj) if not user_obj: res["code"]=1001 res["msg"]="用户名或者密码错误" else: token=get_random_str(user) UserToken.objects.update_or_create(user=user_obj,defaults={"token":token}) res["token"]=token except Exception as e: res["code"]=1002 res["msg"]=e return JsonResponse(res,json_dumps_params={"ensure_ascii":False})
全局视图认证组件
settings.py配置如下:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",] }
权限组件
局部视图权限
在app01.service.permissions.py中:
from rest_framework.permissions import BasePermission class SVIPPermission(BasePermission): message="SVIP才能访问!" def has_permission(self, request, view): if request.user.user_type==3: return True return False
在views.py:
from app01.service.permissions import * class BookViewSet(generics.ListCreateAPIView): permission_classes = [SVIPPermission,] queryset = Book.objects.all() serializer_class = BookSerializers
全局视图权限
settings.py配置如下:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",] }
throttle(访问频率)组件
局部视图throttle
在app01.service.throttles.py中:
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])
在views.py中:
from app01.service.throttles import * class BookViewSet(generics.ListCreateAPIView): throttle_classes = [VisitThrottle,] queryset = Book.objects.all() serializer_class = BookSerializers
全局视图throttle
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] }
内置throttle类
在app01.service.throttles.py修改为:
class VisitThrottle(SimpleRateThrottle): scope="visit_rate" def get_cache_key(self, request, view): return self.get_ident(request)
settings.py设置:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",], "DEFAULT_THROTTLE_RATES":{ "visit_rate":"5/m", } }
根据访问频率组件Throttle 设计一个程序:
每分钟同一个IP只能访问十次
from django.db import models # Create your models here. class Userinfo(models.Model): name=models.CharField(max_length=32,verbose_name='用户名') pwd=models.CharField(max_length=32,verbose_name='密码') token=models.CharField(max_length=64,null=True) def __str__(self): return self.name
from django.shortcuts import render # Create your views here. import time from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.throttling import BaseThrottle from rest_framework import exceptions # Create your views here. AllOW = {} class MyThrottle(BaseThrottle): ''' 限制每分钟访问10次 ''' ip = '127.0.0.1' def allow_request(self, request, view): ctime = time.time() # 当前时间。 ip = self.ip # IP。 if ip not in AllOW: # 如果IP不在ALLOW里面。 AllOW[ip] = [ctime, ] # 为IP设置一个当前时间。 else: time_list = AllOW[ip] # IP对应的访问时间。 while True: if not time_list: # 这里加判断是为了防止,在time_list中没有值的时候会报错。 break if ctime - 60 > time_list[-1]: # 当当前的时间减去60,大于最初的时间。 time_list.pop() # 自动去掉最初的一条记录。 else: break if len(AllOW[ip]) > 9: # 如果一分钟内,IP的访问次数超过10次。 return False AllOW[ip].insert(0, ctime) return True def wait(self): ip = self.ip ctime = time.time() first_in_time = AllOW[ip][-1] wt = 60 - (ctime - first_in_time) # 等待时间,当前时间减去最后一次的时间得到的一个数,然后再使用60秒减去这个数。 return wt class Limitview(APIView): throttle_classes = [MyThrottle,] # 请求频率的设置为MyThrottle def get(self, request): return Response('欢迎进入python的世界!!!') def throttled(self, request, wait): class InnerThrottled(exceptions.Throttled): default_detail = '您的请求已被限制.' extra_detail_singular = 'Expected available in {wait} second.' extra_detail_plural = '请耐心等待{wait}秒' raise InnerThrottled(wait)
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^Limitview/',views.Limitview.as_view()) ]
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ # "app01.utils.MyAuthentication", # "app02.utils.MyAuthentication", ], "DEFAULT_PERMISSION_CLASSES":[ # "app02.utils.MyPermission", # "app02.utils.AdminPermission", ], "DEFAULT_THROTTLE_RATES":{ 'tiga':'10/m', } }
那么我们还可以把认证,权限与频率组合起来进行一个访问频率限制:
from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import BasePermission from rest_framework.throttling import SimpleRateThrottle from rest_framework import exceptions from app01 import models # Create your views here. class MyAuthentication(BaseAuthentication): def authenticate(self, request): token=request.query_params.get(‘token‘) user=models.Userinfo.objects.filter(token=token).first() if user: return (user.name,user) return None class UserPermission(BasePermission): message=‘登录用户才可以访问‘ def has_permission(self, request, view): if request.user: return True return False class AdminPermission(BasePermission): message=‘管理员才能访问‘ def has_permission(self, request, view): if request.user ==‘ctz‘: return True return False class AnnoThrottle(SimpleRateThrottle): scope = ‘anno‘ def get_cache_key(self, request, view): #如果是匿名用户则执行 if not request.user: return self.get_ident(request) #如果不是匿名用户则让他执行 return None class UserThrottle(SimpleRateThrottle): scope = ‘user‘ def get_cache_key(self, request, view): #当前用户登陆了,并且当前用户不是管理员 if request.user and request.user!=‘ctz‘: return self.get_ident(request) #如果是匿名用户和管理员 则让他继续执行 return None class AdminThrottle(SimpleRateThrottle): scope = ‘admin‘ def get_cache_key(self, request, view): #如果是管理员 if request.user==‘ctz‘: return self.get_ident(request) #不是管理员 return None class IndexView(APIView): ‘‘‘ 要求,所有用户都能访问,匿名用户5/m,普通用户10/m,管理员不限 ‘‘‘ authentication_classes = [MyAuthentication,] permission_classes = [] throttle_classes = [AnnoThrottle,UserThrottle,AdminThrottle] def get(self,request): return Response(‘首页‘) def throttled(self, request, wait): class UserInnerThrottled(exceptions.Throttled): default_detail = ‘请求被限制.‘ extra_detail_singular = ‘Expected available in {wait} second.‘ extra_detail_plural = ‘还需要再等待{wait}秒‘ raise UserInnerThrottled(wait) class UserView(APIView): ‘‘‘ 要求:登录用户能访问,普通用户10/m,管理员20/m ‘‘‘ authentication_classes = [MyAuthentication,] permission_classes = [UserPermission,] throttle_classes = [UserThrottle,AdminThrottle] def get(self,request): return Response(‘用户界面‘) def permission_denied(self, request, message=None): """ If request is not permitted, determine what kind of exception to raise. """ if request.authenticators and not request.successful_authenticator: raise exceptions.NotAuthenticated(‘无权访问‘) raise exceptions.PermissionDenied(detail=message) def throttled(self, request, wait): class UserInnerThrottled(exceptions.Throttled): default_detail = ‘请求被限制.‘ extra_detail_singular = ‘Expected available in {wait} second.‘ extra_detail_plural = ‘还需要再等待{wait}秒‘ raise UserInnerThrottled(wait) class ManageView(APIView): ‘‘‘ 要求:只有管理园能访问,5/m ‘‘‘ authentication_classes = [MyAuthentication,] permission_classes = [AdminPermission,] throttle_classes = [AdminThrottle] def get(self,request): return Response(‘管理员界面‘) def permission_denied(self, request, message=None): """ If request is not permitted, determine what kind of exception to raise. """ if request.authenticators and not request.successful_authenticator: raise exceptions.NotAuthenticated(‘无权访问‘) raise exceptions.PermissionDenied(detail=message) def throttled(self, request, wait): class UserInnerThrottled(exceptions.Throttled): default_detail = ‘请求被限制.‘ extra_detail_singular = ‘Expected available in {wait} second.‘ extra_detail_plural = ‘还需要再等待{wait}秒‘ raise UserInnerThrottled(wait)
from django.db import models # Create your models here. class Userinfo(models.Model): name=models.CharField(max_length=32,verbose_name=‘用户名‘) pwd=models.CharField(max_length=32,verbose_name=‘密码‘) token=models.CharField(max_length=64,null=True) def __str__(self): return self.name
REST_FRAMEWORK = { ‘UNAUTHENTICATED_USER‘: None, ‘UNAUTHENTICATED_TOKEN‘: None, "DEFAULT_AUTHENTICATION_CLASSES": [ # "app01.utils.MyAuthentication", "app02.utils.MyAuthentication", ], "DEFAULT_PERMISSION_CLASSES":[ "app02.utils.MyPermission", "app02.utils.AdminPermission", ], "DEFAULT_THROTTLE_RATES":{ ‘tiga‘:‘10/m‘, ‘anno‘:‘5/m‘, ‘user‘:‘10/m‘, ‘admin‘:‘20/m‘, } }
url(r‘^index/‘, views.IndexView.as_view()), url(r‘^user/‘, views.UserView.as_view()), url(r‘^manage/‘, views.ManageView.as_view()),