DRF认证权限频率
认证
DRF提供了关于认证的简单书写方法。
比如用户需要登录后才能访问某个视图:
模型层models.py:
class User(models.Model):
# 用户名
username = models.CharField(max_length=16)
# 密码
password = models.CharField(max_length=16)
# 存储随机字符串用,模仿session
class UserToken(models.Model):
token = models.CharField(max_length=32)
user = models.OneToOneField(to=User, on_delete=models.CASCADE)
认证类:
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class UserAuth(BaseAuthentication):
def authenticate(self, request):
# 假设随机字符串在get请求中
token = request.query_params.get('token')
# 查看获取的随机字符串是否和数据库中的匹配
user_token = UserToken.objects.filter(token=token).first()
if user_token:
# 如果匹配,返回两个值:user对象和随机字符串
return user_token.user, token
# 如果不匹配,代表未登录,抛异常
raise AuthenticationFailed('你还未登录')
视图类(局部配置):
class UserView(APIView):
def post(self, request):
# 用户名
username = request.data.get('username')
# 密码
password = request.data.get('password')
# 获取用户对象
user_obj = User.objects.filter(username=username, password=password).first()
# 判断是否获取到用户对象
if user_obj:
# 获取随机字符串,uuid为内置模块,可生成随机长字符串
token = str(uuid.uuid4())
# 如果数据库中已有token数据,那么就更新,否则添加新token
UserToken.objects.update_or_create(defaults={'token': token}, user=user_obj)
return Response({'code': 100, 'msg': '登录成功', 'token': token})
return Response({'code': 99, 'msg': '用户名或密码错误'})
# 用于测试用户是否已登录用
class BookView(APIView):
# 重写属性,把认证类添加进去(局部配置)
authentication_classes = [UserAuth, ]
def get(self, request):
return Response('BookView get')
路由层:
urlpatterns = [
path('books/', views.BookView.as_view()),
path('login/', views.UserView.as_view()),
]
先登录,获取token字符串
向book/发送请求,如果没携带token,或携带错误的token,会显示未登录
携带正确的token才能正确访问
全局配置
在配置文件中添加:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'认证类路径'
],
}
认证实现原理(源码剖析)
认证、权限、频率三大认证都是在APIView类中实现的。
具体实现通过APIView类中的dispatch()方法:
认证实现方法查看:
user方法,位置在DRF的Request类中,被封装成数据的形式
_authenticate()方法
self.authenticators是在Request实例化的时候传入的,也是在dispatch中实现的
权限
权限的设置与认证的书写十分相似。
模型层:
class User(models.Model):
# 用户名
username = models.CharField(max_length=16)
# 密码
password = models.CharField(max_length=16)
# 权限
role = models.IntegerField(choices=((1, '管理员'), (2, 'VIP'), (3, '普通用户')), default=3)
# 存储随机字符串用,模仿session
class UserToken(models.Model):
token = models.CharField(max_length=32)
user = models.OneToOneField(to=User, on_delete=models.CASCADE)
权限类:
from rest_framework.permissions import BasePermission
class UserPermission(BasePermission):
# 权限不够时返回的信息
message = '只有管理员才能访问'
# 重写方法
def has_permission(self, request, view):
"""view为当前视图"""
# 获取get数据
permission = request.query_params.get('permission')
# 在认证类中返回了user对象,这个对象就是request.user
if request.user.role == 1:
return True
return False
视图类(局部配置):
class UserView(APIView):
authentication_classes = [UserAuth, ]
# 局部配置权限
permission_classes = [UserPermission, ]
def get(self, request):
return Response('BookView get')
全局配置
配置文件中添加:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'权限类路径',
],
}
权限实现原理(源码剖析)
在认证实现原理中了解到:initial方法实现了三大校验
查看check_permissions是怎么实现的
self.get_permissions():
频率
频率,即用户访问服务器的次数。DRF提供了限制频率的类。
频率类编写:
from rest_framework.throttling import SimpleRateThrottle
class MyThrottling(SimpleRateThrottle):
# 名字随意,之后要去配置文件配置
scope = 'rate'
# 需要重写方法
def get_cache_key(self, request, view):
"""这个方法返回什么,就根据什么进行限制"""
# 返回客户端的ip,即限制ip的访问次数
return request.META.get('REMOTE_ADDR')
视图类(局部配置):
class MyView(APIView):
# 重写APIView提供的throttle_classes属性,频率类写进去
throttle_classes = [MyThrottling, ]
def get(self, request):
return Response('MyView')
setting.py配置文件添加:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
# 这里的键为频率类中的scope属性值
'rate': '3/m' # 限制一分钟只能访问三次,h(时)、s(秒)、d(天)
}
}
全局配置
setting.py配置文件添加:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
# 这里的键为频率类中的scope属性值
'rate': '3/m' # 限制一分钟只能访问三次,h(时)、s(秒)、d(天)
},
# 全局生效
'DEFAULT_THROTTLE_CLASSES':['频率类路径']
}
设置提示消息
超出限制的次数后提示消息默认返回的是英文,如果想要自定义消息,需要在视图类中配置:
class MyView(APIView):
# 重写APIView提供的throttle_classes属性,频率类写进去
throttle_classes = [MyThrottling, ]
def get(self, request):
return Response('MyView')
# 固定写法
def throttled(self, request, wait):
from rest_framework.exceptions import Throttled
class MyThrottled(Throttled):
# 默认消息
default_detail = '超限制了,'
# wait参数为单数时显示的内容
extra_detail_singular = '还有最后{wait}秒。'
# wait参数为复数时显示的内容
extra_detail_plural = '还有{wait}秒。'
raise MyThrottled(wait)
自定义频率类
根据IP地址进行限制,一分钟只能访问3次
写法一:
import time
class MyThrottling():
history = {}
wait_time = None
# 一定要有allow_request方法
def allow_request(self, request, view):
# 获取IP地址
client_ip = request.META.get('REMOTE_ADDR')
# 判断客户端是否是第一次发送请求
if client_ip not in self.history:
self.history[client_ip] = [time.time()]
return True
# 去除列表中距当前时间超过出60秒的
for t in self.history[client_ip]:
if time.time() - t > 60:
self.history[client_ip].remove(t)
# 判断客户端一分钟内访问次数
if len(self.history[client_ip]) < 3:
self.history[client_ip].append(time.time())
return True
# 需要等待的时间
self.wait_time = 60 - (time.time() - self.history[client_ip][0])
return False
# wait返回需要等待的时间
def wait(self):
return self.wait_time
写法二(优化写法):
class MyThrottling():
VISIT_RECORD = {}
def __init__(self):
self.history = None
def allow_request(self, request, view):
# (1)取出访问者ip
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])
使用自定义的频率类不需要去配置文件配置,直接在视图类中使用即可。
频率实现原理(源码剖析)
APIView类中的check_throttles校验频率:
self.throttled(request, duration):用于抛出异常
内置认证、权限、频率类
内置认证类
SessionAuthentication:Session认证方式,采用session的方式进行校验。
from rest_framework.authentication import SessionAuthentication
BasicAuthentication:基本认证方式,采用用户名和密码校验。
from rest_framework.authentication import BasicAuthentication
TokenAuthentication:token认证方式,采用token值进行校验。
from rest_framework.authentication import TokenAuthentication
内置权限类
IsAdminUser:只有auth的超级管理员才会有权限(需要用到auth表)。
from rest_framework.permissions import IsAdminUser
IsAuthenticated:只有已登录用户才会有权限。
from rest_framework.permissions import IsAuthenticated
IsAuthenticatedOrReadOnly:只有已登录用户或者发送的请求是('GET', 'HEAD', 'OPTIONS')其中一个才有权限。
from rest_framework.permissions import IsAuthenticatedOrReadOnly
内置频率类
UserRateThrottle:限制登录用户,需要配置配置文件。
from rest_framework.throttling import UserRateThrottle
# UserRateThrottle的scope属性
scope = 'user'
AnonRateThrottle:限制未登录用户,需要配置配置文件。
from rest_framework.throttling import AnonRateThrottle
# AnonRateThrottle的scope属性
scope = 'anon'