drf 认证校验及源码分析

   认证校验是十分重要的,如用户如果不登陆就不能访问某些接口。

   再比如用户不登陆就不能够对一个接口做哪些操作。

   drf中认证的写法流程如下:

   1.写一个类,继承BaseAuthentication,并且覆写其authenticate方法

   2.当认证通过后应该返回两个值,并且第一个值会传递给request.user这个属性中,第二个值将会传递给request.auth这个属性中

   3.如果认证失败,则抛出异常APIException或者AuthenticationFailed,它会自动捕获并返回

   4.当前认证类设置是全局使用还是局部使用

准备工作

   我们有一个登录功能,并且还有一个查询商品的接口,只有当用户登录后才能进行查询,否则就不可以。

模型表

   两张表如下:

from django.db import models class User(models.Model): # 用户 user_id = models.AutoField(primary_key=True) user_name = models.CharField(max_length=32) user_password = models.CharField(max_length=32) user_token = models.CharField(max_length=64,unique=True,null=True) # token,唯一 def __str__(self): return self.user_name class Meta: db_table = "" managed = True verbose_name = "User" verbose_name_plural = "Users" class Merchandise(models.Model): # 商品 merchandise_id = models.AutoField(primary_key=True) merchandise_name = models.CharField(max_length=32) merchandise_price = models.IntegerField() def __str__(self): return self.merchandise_name class Meta: db_table = "" managed = True verbose_name = "Merchandise" verbose_name_plural = "Merchandises"

   用户表的数据如下:

  

image-20201031170412050

   商品表的数据如下:

  

image-20201031171236819

   现在,只有当用户登录后,才能够访问商品的接口。

   也就是说,用户的token自动如果为空,将会被认为没有登陆。

序列类

   下面是序列类,我们只展示商品,用户列表将不会展示:

from rest_framework.serializers import ModelSerializer from . import models class MerchandiseModelSerializer(ModelSerializer): class Meta: model = models.Merchandise fields = "__all__" 视图

   视图,我们只写了关于用户登录与商品的接口:

from uuid import uuid4 from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet from . import models from . import ser from . import authLogin # 导入认证的文件 class MerchandiseAPI(ModelViewSet): queryset = models.Merchandise.objects.all() serializer_class = ser.MerchandiseModelSerializer class Login(APIView): def post(self,request): # 代表用户登录 login_msg = { "user_name": request.data.get("user_name"), "user_password": request.data.get("user_password"), } user_obj = models.User.objects.filter(**login_msg).first() if user_obj: token = uuid4() # 生成随机字符串 user_obj.user_token = token user_obj.save() return Response(data="登录成功",headers={"token":token}) # 返回随机字符串 else: return Response(data="登录失败,用户名或密码错误") url

   使用自动生成路由:

from django.contrib import admin from django.urls import path, re_path from rest_framework.routers import SimpleRouter from app01 import views router = SimpleRouter() router.register("merchandises",views.MerchandiseAPI) urlpatterns = [ path('admin/', admin.site.urls), path('login/',views.Login.as_view()), ] urlpatterns.extend(router.urls) 基本使用 认证类

   接下来我们要书写一个认证类:

from rest_framework.authentication import BaseAuthentication # 继承的基类 from rest_framework.exceptions import AuthenticationFailed # 异常 from . import models from django.http import request class LoginVerify(BaseAuthentication): def authenticate(self, request): token = request.META.get("HTTP_TOKEN") # 如果在请求头中设置的是token的key名,获取时一定要全大写并加上HTTP if not token: raise AuthenticationFailed("请求失败,请求头中缺少token") else: user_obj = models.User.objects.filter(user_token=token).first() # 获取用户对象 if user_obj: return user_obj,user_obj.user_token # 返回用户本身和token。这样request.user里面就能拿到该用户了 else: raise AuthenticationFailed("token不存在,用户不存在,请不要伪造登录") 局部使用

   只需要在商品接口中设置一个类属性,该接口便会进行认证。

class MerchandiseAPI(ModelViewSet): authentication_classes = [authLogin.LoginVerify] # 使用认证 queryset = models.Merchandise.objects.all() serializer_class = ser.MerchandiseModelSerializer 全局使用

   只需要在settings.py中进行配置。

REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.authLogin.LoginVerify",] }

   如果想取消某个接口的认证,则在其中设置类属性authentication_classes是一个空列表。

   如下所示,登录功能不需要验证,我们对他取消掉即可。

class Login(APIView): authentication_classes = [] 源码分析 流程分析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyswxd.html