【一】前言
# 三大认证依次执行 -认证类 -权限类 -频率类 # APIView---->dispatch---》 self.initial(request, *args, **kwargs)--》 self.perform_authentication(request) self.check_permissions(request) self.check_throttles(request)
【二】登录接口(添加认证)
-
用户表 models.py
from django.db import models # Create your models here. class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) age = models.IntegerField() class UserToken(models.Model): token = models.CharField(max_length=64) user = models.OneToOneField(to=User, on_delete=models.CASCADE)
-
视图类 views.py
from rest_framework.viewsets import ViewSet, GenericViewSet from rest_framework.decorators import action from rest_framework.response import Response from .models import User, UserToken class UserView(ViewSet): @action(methods=['POST'], detail=False) def login(self, request): # 取出前端传入的用户和密码 username = request.data.get("username") password = request.data.get("password") # 去数据库校验用户名和密码是否正确 user = User.objects.filter(username=username, password=password).first() if user: # 用户名密码正确,签发token # 使用uuid生成一个随机字符串 uuid:可以生成不重复的字符串 token = str(uuid.uuid4()) # 保存到数据库,update_or_create有则修改,无则添加 UserToken.objects.update_or_create(defaults={"token": token}, user=user) return Response({"code": 200, "msg": "登录成功", "token": token}) else: return Response({"code": 403, "msg": "用户名或密码错误"})
-
自动生成路由并添加 urls.py
from rest_framework.routers import SimpleRouter from .views import UserView # 实例化路由对象 router = SimpleRouter() router.register("user", UserView, "user") urlpatterns = [ ] urlpatterns += router.urls
【三】认证
-
添加book模型表 models.py
class Book(models.Model): name = models.CharField(max_length=32) price = models.IntegerField()
-
视图类 views.py
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, UpdateModelMixin from .models import Book from .serializer import BookSerializer from .auth import LoginAuth class BookView(GenericViewSet, ListModelMixin, RetrieveModelMixin, UpdateModelMixin): authentication_classes = [LoginAuth] queryset = Book.objects.all() serializer_class = BookSerializer
-
序列化类serializer.py
from .models import Book from rest_framework import serializers class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = '__all__'
-
添加路由 urls.py
from .views import UserView,BookView router.register("books", BookView, "book")
-
编写认证类
1 新创建一个py文件 auth ,写一个登录认证类LoginAuth,继承BaseAuthentication 2 在类中,重写authenticate 3 在方法中完成,登录信息的认证 # 要求用户把 登录信息token 放在请求头中 # 取的方法:request.META.get("HTTP_TOKEN") 4 如果认证通过,返回两个值 后续在视图类views.py的方法中 request.user 拿到的就是 第一个参数返回的值 return user_token.user, token 5 认证失败,抛出异常 6 把认证类配置在视图类上--》视图类就会受认证类的控制 局部配置 7 全局配置:配置文件setting中 authentication_classes = [LoginAuth] 8 局部禁用--》登录要局部禁用,空就相当于没有限制 authentication_classes = []
-
auth.py
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from .models import UserToken class LoginAuth(BaseAuthentication): def authenticate(self, request): # 要求用户把登录信息带着请求头中 # 取出token token = request.META.get('HTTP_TOKEN') # 校验用户 user_token = UserToken.objects.filter(token=token).first() if not user_token: # 只能抛出drf异常 raise AuthenticationFailed("当前还未登录,请先前往登录!") else: # 校验通过返回的第一个参数,在views中给了request.user return user_token.user, token
【tips】
在settings中,导入一些不用的模块,可能会导致项目启动不了 例如:from app01.auth import LoginAuth
【四】权限
-
编写权限类
1 新创建一个py文件 permission.py 写一个权限校验类CommonPermission 继承 BasePermission 2 在类中重写has_permission方法 3 在方法中完成,权限的校验 4 如果有权限,返回True 5 如果没有权限,返回False,通过 self.message 修改 错误提示 6 把权限类配置在视图类上--》视图类就会受权限类的控制 -局部配置: permission_classes = [CommonPermission] 7 全局配置:配置文件 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ], 8 局部禁用--》登录要局部禁用 permission_classes = []
-
permission.py
from rest_framework.permissions import BasePermission class CommonPermission(BasePermission): def has_permission(self, request, view): # 判断用户是否有权限 # 取出用户的类型 user_type = request.user.user_type # 对类型进行判断 # 判断是否为超级会员 if user_type == 3: # 如果有权限,返回True return True # 判断是否为普通会员 elif user_type == 2 and request.method in ["GET"]: return True else: self.message = f"你是{request.user.get_user_type_display()},不是会员用户,请升级会员!" return False
【五】频率
-
编写频率类
限制用户的访问频次 - 限制条件是唯一的:ip地址,用户id,设备id号 1 新创建一个py文件 throttles.py 写一个频率校验类CommetnThrottle 继承 SimpleRateThrottle 2 在类中重写get_cache_key方法 3 在方法中完成,频率的校验 4 rate = '3/m' 一分钟三次 5 把频率类配置在视图类上--》视图类就会受频率类的控制 局部配置: throttle_classes = [CommontThrottle] 6 全局配置:配置文件 DEFAULT_THROTTLE_CLASSES': ['自己写的类'], 7 局部禁用--》登录要局部禁用 throttle_classes = []
-
throttles.py
from rest_framework.throttling import SimpleRateThrottle # SimpleRateThrottle继承自 BaseThrottle 因为使用更方便所以导入它就可以了 class CommentThrottle(SimpleRateThrottle): # 一分钟三次 rate = '3/m' def get_cache_key(self, request, view): # 返回什么,就以什么做限制 # ip限制 ip = request.META.get('REMOTE_ADDR') # id限制 # user_id = request.user.id return ip