drf认证、权限、频率
认证Authentication(5星)
认证逻辑及编写步骤
逻辑
认证类:用来校验用户是否登录,如果登录了,继续往下走,如果没有登录,直接返回
编写步骤
-第一步:写一个类,继承BaseAuthentication,重写authenticate,在方法中做校验,校验是否登录,返回两个值,没有登录抛异常
-第二步:全局配置,局部配置
-全局配置:配置文件中
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth",]
}
-局部配置:在视图类中
class UserView(ViewSet):
authentication_classes = [LoginAuth]
-局部禁用:
class UserView(ViewSet):
authentication_classes = []
# 认证类中返回的两个变量,干啥用了
-返回的第一个,给了request.user,就是当前登录用户
-返回的第二个,给了request.auth,就是token串
使用方法
新建一个功能为认证的py文件,然后在里面书写下面代码
from rest_framework.authentication import BaseAuthentication # 类必须继承这个
from rest_framework.exceptions import AuthenticationFailed # 认证报错的异常
class xxx(BaseAuthentication):
def authenticate(self, request): # 必须重写这个方法,不然报错
逻辑逻辑逻辑...
if 验证通过:
return
else:
raise AuthenticationFailed('验证不通过')
在需要验证的视图类里
class BookAPIView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
# 只需要把下面这句话加上就行了 那么在执行该视图类前会判断该类是否通过验证
# 通过则正常执行,不通过则返回报错信息
authentication_classes = [xxx, ]
案例
登陆认证
在路由里:
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('book', views.BookAPIView)
urlpatterns = [
path('login/', views.UserView.as_view()),
path('', include(router.urls))
]
在models.py里:
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
class UserToken(models.Model):
user = models.OneToOneField(to='User', on_delete=models.CASCADE)
token = models.CharField(max_length=64)
在认证的py文件里:
# 新建一个py文件auth.py
from rest_framework.authentication import BaseAuthentication
from .models import UserToken
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
#### 写认证规则
# 取出用户携带的token
token = request.query_params.get('token')
# 去数据库查找
user_token = UserToken.objects.filter(token=token)
if user_token:
# 说明登陆过
'''
如果返回user,token,后面视图类中通过request对象,可以取到当前登录用户
'''
return
else:
# 没有登录,不能继续往后走,抛认证失败异常
raise AuthenticationFailed('您未登陆')
在视图函数里:
from app01.auth import LoginAuth
class BookAPIView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
authentication_classes = [LoginAuth, ] # 这里验证是否登陆
因为数据库内已经有一个token,所以拿这个token验证
全局使用
在django的settings.py中设置
这里不要手打,容易出错,用模块导入的形式来写
from app01.auth import LoginAuth
然后把import删除加个点
app01.auth.LoginAuth
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth",]
}
局部使用
# 局部使用,只需要在视图类里加入:
authentication_classes = [LoginAuth, ]
# 局部禁用 直接写个空列表就行了
authentication_classes = []
认证类的查找顺序
视图类自己中的authentication_classes > 项目的配置文件 > drf的配置文件
源码分析(2星)
# APIView--->dispathch方法的-----》self.initial(request, *args, **kwargs)(497行)---》APIView的initial方法----》有三句话
self.perform_authentication(request) # 认证
self.check_permissions(request) # 权限
self.check_throttles(request) # 频率
补充知识点:
权限Permissions(4星)
使用方法
在一个py文件内:
from rest_framework.permissions import BasePermission # 继承这个类
class xxx(BasePermission):
def has_permission(self, request, view): # 重写此方法
# 写权限逻辑
if 符合权限:
return True # 有权限
else:
return False # 无权限
在需要验证的视图类里:
# 把权限的py文件导入
class BookAPIView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
# 只需要把下面这句话加上就行了 那么在执行该视图类前会判断该类是否有权限
# 没权限则不会执行该视图类
permission_classes = [xxx, ]
全局使用
REST_FRAMEWORK={
"DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",]
}
局部使用
# 局部使用只需要在视图类里加入:
permission_classes = [UserPermission,]
# 局部禁用
permission_classes = [] # 什么都不写就是不需要任何权限,甚至不需要验证token
对象级别的权限
REST框架权限还支持对象级的许可。对象级权限用于确定是否允许用户操作特定对象(通常是模型实例)。
当调用.get_object()
时,由REST框架的通用视图运行对象级权限检测。 与视图级别权限一样,如果不允许用户操作给定对象,则会抛出exceptions.PermissionDenied
异常。
如果你正在编写自己的视图并希望强制执行对象级权限检测,或者你想在通用视图中重写get_object
方法,那么你需要在检索对象的时候显式调用视图上的.check_object_permissions(request, obj)
方法。
这将抛出PermissionDenied
或NotAuthenticated
异常,或者如果视图具有适当的权限,则返回。
例如:
def get_object(self):
obj = get_object_or_404(self.get_queryset())
self.check_object_permissions(self.request, obj)
return obj
因为check_object_permissions方法会调用has_object_permission方法,所以你可以重写has_object_permission方法
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
def has_permission(self, request, view):
pass
def has_object_permission(self, request, view, obj): # 重写这个方法就可以了
pass
源码分析(2星)
和认证的源码差不多,只是没有和Request联系
APIView---》dispatch-self.initial---》self.check_permissions(request)
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
频率Throttling
可以对接口访问的频次进行限制,以减轻服务器压力。
一般用于付费购买次数,投票等场景使用.
继承SimpleRateThrottle使用方法
这里继承SimpleRateThrottle
在一个py文件内:
from rest_framework.throttling import SimpleRateThrottle # 必须继承这个类
class xxx(SimpleRateThrottle):
scope = 'ip_throtle' # 这个参数必须配置,不然会报错,后面的字符串随便写
# 或者
rate = '3/m' # 这样写下面的配置文件里的'ip_throtle': '3/m'就可以不用写了,并且scope不用配置了
def get_cache_key(self, request, view):
# 返回客户端IP 返回谁,就以谁做限制 按ip限制(如果是按其他条件限制就取其他条件的参数,比如手机号)
return request.META.get('REMOTE_ADDR')
# 或
return self.get_ident(request) # 如果有代理也会返回真实的客户端IP
在配置文件settings.py内:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'ip_throtle': '3/m' # key要跟类中的scope对应 '3/m'意思是每分钟最多访问3次
}
}
# 使用 `second`, `minute`, `hour` 或`day`来指明周期。
在需要验证限流的视图类里:
from app01.auth import xxx
class BookAPIView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
throttle_classes = [xxx, ] # 在这里添加验证限流
全局使用
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': ['app01.auth.MyThrottle'], # 全局使用
'DEFAULT_THROTTLE_RATES': {
'ip_throtle': '3/m' # key要跟类中的scope对应 '3/m'意思是每分钟最多访问3次
}
}
局部使用
class BookView(ViewSetMixin,ListAPIView):
throttle_classes = [MyThrottle,]
源码分析SimpleRateThrottle(2星)
继承BaseThrottle使用方法
# 自定义的逻辑
#(1)取出访问者ip
#(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
#(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
#(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
#(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
# {'ip1':[时间1,时间2,时间3], 'ip2':[时间1,时间2]}
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])
源码分析BaseThrottle(2星)
APIVIew的dispatch---》self.initial(request, *args, **kwargs)----》
def check_throttles(self, request):
throttle_durations = []
for throttle in self.get_throttles():
if not throttle.allow_request(request, self):
throttle_durations.append(throttle.wait())
if throttle_durations:
durations = [
duration for duration in throttle_durations
if duration is not None
]
duration = max(durations, default=None)
self.throttled(request, duration)
AnonRateThrottle
AnonRateThrottle
会限制未经身份验证的用户。传入请求的IP地址用于生成唯一的密钥以进行限制。
允许的请求频次由以下之一确定(按优先顺序)。
- 类的
rate
属性,可以通过重写AnonRateThrottle
并设置该属性来提供。 DEFAULT_THROTTLE_RATES['anon']
设置。
如果要限制来自未知源的请求速率,则AnonRateThrottle
是合适的。
REST_FRAMEWORK = {
# 限速类
'DEFAULT_THROTTLE_CLASSES': [
# 用户没有登入的情况下 AnonRateThrottle通过ip地址来判断的
'rest_framework.throttling.AnonRateThrottle',
# 用户登入的情况下 UserRateThrottle通过token, session来判断的
'rest_framework.throttling.UserRateThrottle'
],
# 限速规则
'DEFAULT_THROTTLE_RATES': {
# 匿名用户 最多一分钟访问60次
'anon': '60/minute',
# 登入用户 最多一分钟访问60次
'user': '60/minute'
}
}
UserRateThrottle
UserRateThrottle
将通过API将用户限制为给定的请求速率。用户ID用于生成唯一的密钥以进行限制。未经身份验证的请求将退回到使用传入请求的IP地址来生成唯一密钥以进行限制。
允许的请求速率由以下之一确定(按优先顺序)。
- 类的
rate
属性,可以通过重写UserRateThrottle
并设置该属性来提供。 DEFAULT_THROTTLE_RATES['user']
设置。
一个API可能同时具有多个 UserRateThrottles
。为此,请重写 UserRateThrottle
并为每个类设置一个唯一的“作用域”。
例如,可以通过使用以下类来实现多个用户节流率...
class BurstRateThrottle(UserRateThrottle):
scope = 'burst'
class SustainedRateThrottle(UserRateThrottle):
scope = 'sustained'
...和以下设置。
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
'example.throttles.BurstRateThrottle',
'example.throttles.SustainedRateThrottle'
),
'DEFAULT_THROTTLE_RATES': {
'burst': '60/min',
'sustained': '1000/day'
}
}
UserRateThrottle
如果您想对每个用户进行简单的全局速率限制,则适用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了