一. 认证
(你是谁?)
REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案。
自定义Token认证
第一步 : 建表>>>>
定义一个用户表和一个保存用户Token的表
class UserInfo(models.Model): username = models.CharField(max_length=16) password = models.CharField(max_length=32) type = models.SmallIntegerField( choices=((0, '普通用户'), (1, 'VIP用户')), default=0 ) class Token(models.Model): user = models.OneToOneField(to='UserInfo') token_code = models.CharField(max_length=128)
第二步: 定义一个登陆视图 >>>>
from rest_framework.views import APIView from app2 import models from rest_framework.response import Response import hashlib, time def get_random_token(username): """ 根据用户名和时间戳生成随机token """ timestamp = str(time.time()) m = hashlib.md5(bytes(username, encoding="utf-8")) m.update(bytes(timestamp, encoding="utf-8")) return m.hexdigest() class LoginView(APIView): """ 校验用户名是否正确从而生成token的视图 """ def post(self, request): res = {"code": 0} # print(request.data) username = request.data.get("username") password = request.data.get("password") user = models.UserInfo.objects.filter(username=username, password=password).first() if user: token = get_random_token(username) models.Token.objects.update_or_create(defaults={"token_code": token}, user=user) res["token"] = token else: res["code"] = 1 res["error"] = "用户名或密码错误" return Response(res)
第三步: 定义一个认证类 >>>>
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from app2 import models class MyAuth(BaseAuthentication): def authenticate(self, request): # if request.method in ["POST", "PUT", "DELETE"]: # 如果在表单中需要判断请求方式 由于表单是post请求,所以获取token 的方式为 request.data.get("token") # request.query_params为url中的参数 request_token = request.query_params.get("token", None) if not request_token: raise AuthenticationFailed('q.缺少token') token_obj = models.Token.objects.filter(token_code=request_token).first() if not token_obj: raise AuthenticationFailed("无效的Token") # token_obj.user 通过token这张表的对象和user这个关联字段 找到 UserInfo表的对象及当前用户对象 return token_obj.user, request_token # else: # return None, None
第四步: 使用认证类 >>>>
视图级别认证
class CommentViewSet(ModelViewSet): queryset = models.Comment.objects.all() serializer_class = app01_serializers.CommentSerializer authentication_classes = [MyAuth, ]
全局级别认证
# 在settings.py中配置 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ] }
二. 权限
(你能干什么?) 设置只有VIP才能看到的东西
第一步: 自定义一个权限类
""" 自己动手写一个权限组件 """ from rest_framework.permissions import BasePermission class MyPermission(BasePermission): message = '只有VIP才能访问' def has_permission(self, request, view): # 认证类中返回了token_obj.user, request_token # request.auth 等价于request_token if not request.auth: return False # request.user为当前用户对象 if request.user and request.user.type == 1: # 如果是VIP用户 print("requ", request.user, type(request.user)) return True else: return False
第二步: 使用
视图级别配置
class CommentViewSet(ModelViewSet): queryset = models.Comment.objects.all() serializer_class = app01_serializers.CommentSerializer authentication_classes = [MyAuth, ] permission_classes = [MyPermission, ]
全局级别设置
# 在settings.py中设置rest framework相关配置项 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ], "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ] }
三. 控制
(你一分钟能干多少次?)**好像有点污~~
第一步: 自定义限制类 >>>>
import time # from rest_framework.throttling import visit_record = {} class MyThrottle(object): def __init__(self): self.history = None def allow_request(self, request, view): # 拿到当前的请求的ip作为访问记录的 key ip = request.META.get('REMOTE_ADDR') # 拿到当前请求的时间戳 now = time.time() if ip not in visit_record: visit_record[ip] = [] # 把当前请求的访问记录拿出来保存到一个变量中 history = visit_record[ip] self.history = history # 循环访问历史,把超过10秒钟的请求时间去掉 while history and now - history[-1] > 10: history.pop() # 此时 history中只保存了最近10秒钟的访问记录 if len(history) >= 3: return False else: # 判断之前有没有访问记录(第一次来) self.history.insert(0, now) return True def wait(self): """告诉客户端还需等待多久""" now = time.time() return self.history[-1] + 10 - now # history = ['9:56:12', '9:56:10', '9:56:09', '9:56:08'] # '9:56:18' - '9:56:12' # history = ['9:56:19', '9:56:18', '9:56:17', '9:56:08'] # 最后一项到期的时间就是下一次允许请求的时间 # 最后一项到期的时间:now - history[-1] > 10 # 最后一项还剩多少时间过期 # history[-1] + 10 - now
第二步: 使用 >>>
视图中使用
class CommentViewSet(ModelViewSet): queryset = models.Comment.objects.all() serializer_class = app01_serializers.CommentSerializer throttle_classes = [MyThrottle, ]
全局中使用
# 在settings.py中设置rest framework相关配置项 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ], "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ] "DEFAULT_THROTTLE_CLASSES": ["app01.utils.MyThrottle", ] }
其实还可以使用内置限制类
from rest_framework.throttling import SimpleRateThrottle class VisitThrottle(SimpleRateThrottle): scope = "xxx" def get_cache_key(self, request, view): return self.get_ident(request)
全局配置
# 在settings.py中设置rest framework相关配置项 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ], # "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ] "DEFAULT_THROTTLE_CLASSES": ["app01.utils.VisitThrottle", ], "DEFAULT_THROTTLE_RATES": { "xxx": "5/m", } }
看源码:
1.认证流程
2. 权限