05-视图类的选择以及三大认证
如何选择视图类?
视图类 | 如何选择 | 场景举例 |
---|---|---|
APIView | 不会和数据库打交道,不会用到序列化类。 | 发送短信接口,发送邮件接口 |
GenericAPIView | 需要和数据库以及序列化类打交道,就需要继承它。 | 注册,登录 |
5个视图扩展类 | 单独某一个功能接口(注意:需要搭配GenericAPIView一起使用) | 单纯增删改查单一功能 |
9个视图子类 | 如果要写5个接口N个,直接使用视图子类 | 新增 |
ViewSet | 原来继承APIView,如果想要自动生成路由,或者自定义路由映射,就需要继承它 | send_sms |
GenericViewSet | 原来继承GenericAPIView,但是想自动生成路由或路由映射,就继承他 | |
ModelViewSet | 5个接口,自动生成路由 | 很少用到 |
三大认证(认证,权限,频率)
注意:三大认证每一个认证都建立一个独立的模块。
- 认证
- 权限
- 频率
这几个是依次来的,也就是如果前面的没有认证成功,不会走到后面的
- 没有登录,无法使用认证权限
登录认证 BaseAuthentication
- 用户登录成功,签发token
- token一般通过headers去返回
- 一般有两个表,一个user表,一个user_token表,一对一关联
- request.META.get('
HTTP_TOKEN
') ,获取token
怎么使用
from from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
1. 写一个类 继承 BaseAuthentication
- 注意,这个类不建议写在视图层,建议新开一个模块去写,然后导入
2. 重写 authenticate 方法
3. 在 authenticate 方法中完成用户的校验
- 如何验证登录了
- 用户携带token,能查询到,就是登录了
- 用户没带,查询不到,就是没登录
4. 如果验证通过,就返回当前用户和token
5. 如果验证失败,就抛 AuthenticationFailed 异常
局部认证 类属性
# authentication.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import UserToken
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
# 这里的request是新的request ,因为三大认证是包装之后才走的
token = request.META.get("HTTP_TOKEN")
print(token)
# token 放在哪里,这个是后端去工程师去定义的,一般放在请求头中。
# 校验
user_token = UserToken.objects.filter(token=token).first()
if token:
# 一对一的跨表查询
user = user_token.user
print("user", user, "token", token)
return user, token
else:
raise AuthenticationFailed("很抱歉,需要登录才能使用该功能!")
# 视图
from rest_framework.mixins import ListModelMixin, CreateModelMixin, DestroyModelMixin
from rest_framework.viewsets import GenericViewSet
from .sarialinzer import BookSerializer
from .models import Book
from .authentication import LoginAuth
class BookView(GenericViewSet, ListModelMixin, CreateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
authentication_classes = [LoginAuth]
全局认证
# 这里导入认证需要使用绝对路径了
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
"user.authentication.LoginAuth" # user是名称 authentication 自己定义的模块 LoginAuth 认证函数
],
}
局部取消认证 类属性
authentication_classes = [ ]
权限认证 permissions
权限认证,指的是用户正常登录后,能看到哪一些属于自己的权限,比如超级管理员有增删查改的全部功能,而普通用户只有查看的功能。
- 权限通过返回True 权限未通过 返回False
权限认证的模型层
一般通过choice去控制权限,后续取出来对应的数据即可 ,一般建议设置一个默认值default
from django.db import models
class UserProfile(modes.Model):
gender_list = [
(0, "男"),
(1, "女")
]
# 存进去 用0 或者 1
sex = models.IntegerField(choices=gender_list)
# 取出来 get_字段名_display()
user = UserProfile.objects.get(id=1)
sex_display = user.get_sex_display()
print(sex_display)
使用
# 导入模块
from rest_framework.permissions import BasePermission
# 定义一个类继承它
class UserPermission(BasePermission):
# 重写该方法
# request就是HTTP请求,view就是视图层的实例
def has_permission(self, request, view):
...
# 如果有权限 返回True
# 如果没有权限 返回False
# 视图层
from .permissions import UserPermission
class PublishView(GenericViewSet):
# authentication_classes = [LoginAuth] 登录认证
permission_classes = [UserPermission] # 权限认证 因为登录后才有权限
拿到当前登录用户 request.user
前提是用户已经通过了登录认证
# 登录认证类
if token:
# 一对一的跨表查询
user = user_token.user
print("user", user, "token", token)
return user, token # 也就是这里返回的user 去到了request.user中了
自定义返回信息 self.message
# 一定要这个名字 不能写错了
user_type = user.get_user_type_display()
self.message = f"很抱歉,您是{user_type},没有权限访问。"
return False # 别忘记return
全局配置
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
"v1.permissions.UserPermission"
],
}
局部配置
from .permissions import UserPermission
class PublishView(GenericViewSet):
# authentication_classes = [LoginAuth] 登录认证
permission_classes = [UserPermission] # 权限认证 因为登录后才有权限
局部禁用
permission_classes = [ ]
注意:后续的权限判断可能会比较复杂
# 基于ACL权限控制 ,就是权限放进去一个列表里面,去校验
1. 多表关联
2. 一个用户有发抖音,开直播,等很多权限
3. 一个用户可能有10个接口或者更多
...
# 不论多么复杂的权限,都是return True 或者 False
频率认证 BaseThrottle, SimpleRateThrottle
- 这个认证一定是在登录认证,以及权限认证都通过以后,才走到频率认证的
导入模块
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
如何使用
# 导入模块
from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
# 写一个类 继承它
class CommonThrottling(SimpleRateThrottle):
# 设置频率限制
# 限制在这里设置
rate = "3/m" # 这个意思就是 1分钟三次 次数/时间 m分钟 h小时 s秒
# 重写方法
def get_cache_key(self, request, view):
# 这里返回什么, 就用什么去做限制 一般是用户id 以及 ip地址
# 别忘记return
# 根据ip地址去限制
return request.META.get("REMOTE_ADDR")
一般用什么去做限制 IP地址,用户ID
设备ID?
- 手机可以,网页端不可以
想想爬虫,都是用限制唯一标识
rate 设置限制次数 次数/时间
在 SimpleRateThrottle
中,rate
参数可以接受的格式为 "num_requests/period"
,其中 num_requests
表示限制的请求数量,period
表示时间段,可以是 "s"
(秒)、"m"
(分钟)、"h"
(小时)等单位。
3/m 1分钟3次
3/h 1小时3次
3/d 1天3次
3/s 1秒3次
局部使用
# 视图层
from .throttling import CommonThrottling
# 限制超级管理员才可以访问
class PublishView(GenericViewSet):
throttle_classes = [CommonThrottling]
# ...
全局使用
自定义配置
REST_FRAMEWORK = {
'DEFAULT_THORTTLING_CLASSES': ["v1.throttling.CommonThrottling"]
}
自带配置
默认限制策略可以使用 DEFAULT_THROTTLE_CLASSES
和 DEFAULT_THROTTLE_RATES
设置进行全局设置。例如:
REST_FRAMEWORK = {
# 设置限流器类
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle', # 匿名用户
'rest_framework.throttling.UserRateThrottle' # 登录用户
],
# 限流速率
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day', # 匿名频次 # anon:这个key名是AnonRateThrottle类的专属,表示AnonRateThrottle类的限流速率
'user': '1000/day' # 登录频次
}
}
局部禁用
throttle_classes = [ ]
频率限制装饰器 【第三方/FBV推荐】
在 Django 中,可以使用 django_ratelimit
库提供的装饰器来实现频率限制。这个库允许你在视图函数上设置访问速率限制,可以限制来自 IP 地址的请求速率或者限制来自用户的请求速率。
以下是一个简单的示例,演示如何在 Django 中使用 django_ratelimit
库来设置频率限制:
from django.http import HttpResponse
from django.shortcuts import render
from django_ratelimit.decorators import ratelimit
@ratelimit(key='ip', rate='5/m', method='GET', block=True)
def my_view(request):
return HttpResponse("You are not allowed to perform this action too frequently.")
在上面的示例中:
@ratelimit
装饰器用于标记需要进行频率限制的视图函数。key='ip'
指定了限制的键,这里是 IP 地址。你也可以选择使用'user'
来根据用户进行限制。rate='5/m'
设置了访问速率限制为每分钟 5 次。method='GET'
表示仅对 GET 请求进行频率限制。block=True
表示如果频率超出限制,则返回 HTTP 429 Too Many Requests 响应。
本文作者:小满三岁啦
本文链接:https://www.cnblogs.com/ccsvip/p/18139567
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。