05-视图类的选择以及三大认证

如何选择视图类?

视图类 如何选择 场景举例
APIView 不会和数据库打交道,不会用到序列化类。 发送短信接口,发送邮件接口
GenericAPIView 需要和数据库以及序列化类打交道,就需要继承它。 注册,登录
5个视图扩展类 单独某一个功能接口(注意:需要搭配GenericAPIView一起使用) 单纯增删改查单一功能
9个视图子类 如果要写5个接口N个,直接使用视图子类 新增
ViewSet 原来继承APIView,如果想要自动生成路由,或者自定义路由映射,就需要继承它 send_sms
GenericViewSet 原来继承GenericAPIView,但是想自动生成路由或路由映射,就继承他
ModelViewSet 5个接口,自动生成路由 很少用到

三大认证(认证,权限,频率)

注意:三大认证每一个认证都建立一个独立的模块。

  1. 认证
  2. 权限
  3. 频率

这几个是依次来的,也就是如果前面的没有认证成功,不会走到后面的

  • 没有登录,无法使用认证权限

登录认证 BaseAuthentication

  1. 用户登录成功,签发token
  2. token一般通过headers去返回
  3. 一般有两个表,一个user表,一个user_token表,一对一关联
  4. 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

  1. 这个认证一定是在登录认证,以及权限认证都通过以后,才走到频率认证的

导入模块

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_CLASSESDEFAULT_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 响应。
posted @ 2024-04-16 23:33  小满三岁啦  阅读(8)  评论(0编辑  收藏  举报