认证是确定你是谁
权限是指你有没有访问这个接口的权限
限制主要是指限制你的访问频率
认证
REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案。
接下类我们就自己动手实现一个基于Token的认证方案:
自定义Token认证
表
定义一个用户表和一个保存用户Token的表:
# 用户表 class UserInfo(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) vip = models.BooleanField(default=False) token = models.CharField(max_length=128, null=True, blank=True)
视图:
定义一个登陆视图
class LoginView(APIView): def post(self, request): name = request.data.get('name') pwd = request.data.get('pwd') if name and pwd: user_obj = models.UserInfo.objects.filter(name=name, pwd=pwd).first() if user_obj: # 登陆成功 # 生成token(时间戳 + Mac地址) token = uuid.uuid1().hex # 1.保存在用户表中 user_obj.token = token user_obj.save() # 2.给用户返回 return Response({'error_no': 0, 'token': token}) else: # 用户名或密码错误 return Response({'error_no': 1, 'error': '用户名或密码错误'}) else: return Response('无效的参数')
定义一个认证类
from rest_framework.authentication import BaseAuthentication from auth_demo import models from rest_framework.exceptions import AuthenticationFailed # 抛错时使用 class MyAuth(BaseAuthentication): def authenticate(self, request): token = request.query_params.get('token') if token: # 如果请求的URL中携带了token参数 user_obj = models.UserInfo.objects.filter(token=token).first() if user_obj: # token是有效的 return user_obj, token # request.user, request.auth else: raise AuthenticationFailed('无效的token') else: raise AuthenticationFailed('请求的URL中必须携带token参数')
视图级别的认证:
class TestAuthView(APIView): authentication_classes = [MyAuth, ] # 局部配置认证 permission_classes = [MyPermission, ] def get(self, request): print(request.user.name) print(request.auth) return Response('这个视图里面的数据只有登录后才能看到!')
全局级别认证
# 在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): if not request.auth: # 用户登录确认 return False # 如果你是VIP才有权限访问 # request.user:当前经过认证的用户对象 if request.user.vip: return True else: # 如果不是VIP就拒绝范围跟 return False
视图级别认证:
class TestAuthView(APIView): authentication_classes = [MyAuth, ] # 局部配置认证 permission_classes = [MyPermission, ] # 权限局部认证 def get(self, request): print(request.user.name) print(request.auth) return Response('这个视图里面的数据只有登录后才能看到!')
全局级别设置
# 在settings.py中设置rest framework相关配置项 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ], "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ] }
限制
自定义一个限制访问的类
import time """ 自定义一个限制 """ # 创建一个空的字典 visit = {} class BaseThrottle(object): def __init__(self): self.history = None def allow_request(self, request, view): ip = request.META.get('REMOTE_ADDR') # 获取用户的ip地址 now = time.time() # 获取当前时间 if ip not in visit: # 第一次进来的时候 字典中没有以ip为key的键值对 visit[ip] = [] # 创建一个以ip为key的键值对 history = visit[ip] # 如果不是第一次访问的话 获取一下以ip为key的对应的值 self.history = history # 因为wait方法中也会用到history的值,所以把history升级成类属性 while history and now - history[-1] > 10: # 循环判断一下 如果当前时间与history里面的最先插入的时间大于10秒 history.pop() # 就删除最后的先插入的那个数据 if len(history) >= 3: # 如果10秒内history里面的时间戳大于3个,表示查询过于频繁,限制一下,返回false return False else: # 如果10秒钟内没有三个时间戳,再来访问的话是可以的,记录一下当前访问的时间戳 history.insert(0, now) return True def wait(self): # 这个方法主要是提示用户等待时间的 now = time.time() # 获取当前时间 return self.history[-1]+10 - now # 最早访问的时间减去当前时间
使用
局部使用
class TestView(APIView): authentication_classes = [Myauth, ] # 用户身份验证 permission_classes = [Permissions, ] # 用户权限验证 throttle_classes = [BaseThrottle, ] # 用户访问频率限制 def get(self, request): print(request.user) print(request.auth) return Response("这是会员才可以看到的画面")
全局使用
# 在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", } }