认证组件 1 写一个认证类 from rest_framework.authentication import BaseAuthentication class MyAuth(BaseAuthentication): def authenticate(self,request): # request 是封装后的 token = request.query_params.get('token') ret = models.UserToken.objects.filter(token=token).first() if ret: # 认证通过 return else: raise AuthenticationFailed('认证失败') #可以不写了 def authenticate_header(self,ss): pass 2 局部使用 authentication_classes=[MyAuth,MyAuth2] 3 全局使用 查找顺序:自定义的APIView里找---》项目settings里找---》内置默认的 REST_FRAMEWORK={ 'DEFAULT_AUTHENTICATION_CLASSES':['utils.common.MyAuth',] } 权限组件 1 写一个类 from rest_framework.permissions import BasePermission class MyPermission(BasePermission): message = '不是超级用户,查看不了' def has_permission(self,request,view): token=request.query_params.get('token') ret=models.UserToken.objects.filter(token=token).first() if ret.user.type==2: # 超级用户可以访问 return True else: return False 2 局部使用: permission_classes=[MyPermission,] 3 全局使用: REST_FRAMEWORK={ 'DEFAULT_PERMISSION_CLASSES':['utils.common.MyPermission',] } 频率组件 1 写一个类: from rest_framework.throttling import SimpleRateThrottle class VisitThrottle(SimpleRateThrottle): scope = 'xxx' def get_cache_key(self, request, view): return self.get_ident(request) 2 在setting里配置: 'DEFAULT_THROTTLE_RATES':{ 'xxx':'5/h', } 3 局部使用 throttle_classes=[VisitThrottle,] 4 全局使用 REST_FRAMEWORK={ 'DEFAULT_THROTTLE_CLASSES':['utils.common.VisitThrottle',] }
认证,想局部取消(禁用)比如login登录的时候就需要禁用掉认证
authentication_classes=[]
认证组件 不存数据库的token验证
视图层:
def get_token(id,salt='123'): import hashlib md=hashlib.md5() md.update(bytes(str(id),encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) return md.hexdigest()+'|'+str(id) def check_token(token,salt='123'): ll=token.split('|') import hashlib md=hashlib.md5() md.update(bytes(ll[-1],encoding='utf-8')) md.update(bytes(salt,encoding='utf-8')) if ll[0]==md.hexdigest(): return True else: return False class TokenAuth(): def authenticate(self, request): token = request.GET.get('token') success=check_token(token) if success: return else: raise AuthenticationFailed('认证失败') def authenticate_header(self,request): pass 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_token(user.pk) # 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) 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 class Course(APIView): authentication_classes = [TokenAuth, ] def get(self, request): return HttpResponse('get') def post(self, request): return HttpResponse('post')
频率组件
2 频率: django自带了频率控制类,比如是flask没有这种类的话需要自己写频率控制类 为了控制用户对某个url请求的频率,比如,一分钟以内,只能访问三次 自定义的逻辑 #(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]) 2.1自定义: 1 定义一个类MyThrottles allow_request(频率限制的逻辑) wait(返回一个数字,给用户提示,还差多少秒) 2 局部使用:throttle_classes=[MyThrottles,] 3 全局使用:'DEFAULT_THROTTLE_CLASSES':['utils.common.MyThrottles',], 2.2用内置的:(可以控制ip,和userid) from rest_framework.throttling import SimpleRateThrottle class VisitThrottle(SimpleRateThrottle): scope = 'xxx' def get_cache_key(self, request, view): # 这里可以写按照用户或者ip来限制频率 # ip=rquest.META.get('REMOTE_ADDR') pk = request.user.pk return pk # return self.get_ident(request) 1 写一个类,继承SimpleRateThrottle 属性:scope = 'xxx' 重写方法:get_cache_key 去setting里配置:'DEFAULT_THROTTLE_RATES':{ # 'xxx':'5/m', 'xxx':'5/m', } 2 局部使用:throttle_classes=[MyThrottles,] 3 全局使用:'DEFAULT_THROTTLE_CLASSES':['utils.common.MyThrottles',], 错误信息的中文提示: 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)
版本控制: 取不同url中的版本
url: url(r'^testversion/', views.Test.as_view()), url(r'^(?P<version>[v1|v2|v3]+)/testversion/', views.Test2.as_view(),name='ttt'), 视图: from django.shortcuts import render,HttpResponse # Create your views here. from rest_framework.views import APIView from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning class Test(APIView): versioning_class = QueryParameterVersioning def get(self,request,*args,**kwargs): print(request.version) return HttpResponse('ok') from django.urls import reverse class Test2(APIView): versioning_class = URLPathVersioning def get(self,request,*args,**kwargs): print(request.version) url=request.versioning_scheme.reverse(viewname='ttt',request=request) print(url) url2=reverse(viewname='ttt',kwargs={'version':'v1'}) print(url2) return HttpResponse('ok') 1 127.0.0.1/course/?version=v100000 路由: url(r'^testversion/', views.Test.as_view()), 视图层: 用from rest_framework.versioning import QueryParameterVersioning class Test(APIView): versioning_class = QueryParameterVersioning def get(self,request,*args,**kwargs): print(request.version) return HttpResponse('ok') 在视图类里: versioning_class=QueryParameterVersioning(**不再是列表) 在setting里配置: REST_FRAMEWORK={ 'VERSION_PARAM':'version', 'DEFAULT_VERSION':'v2', 'ALLOWED_VERSIONS':['v1','v2'] } 取: 视图类里: request.version 127.0.0.1/v1/course/ 用from rest_framework.versioning import URLPathVersioning 在视图类里: versioning_class=URLPathVersioning**不再是列表) 在setting里配置: REST_FRAMEWORK={ 'VERSION_PARAM':'version', 'DEFAULT_VERSION':'v2', 'ALLOWED_VERSIONS':['v1','v2'] } 取: 视图类里: request.version 3 反向解析(了解)