DRF从入门到精通五(路由组件、认证组件、权限组件、频率组件及认证、权限源码分析)

news2025/1/24 22:36:18

文章目录

  • 一、路由组件
    • REST framework提供了两个router
    • action装饰器
  • 二、认证组件(Authentication)
  • 三、权限组件(Permissions)
    • 内置权限类
  • 四、频率组件(Throttling)
  • 五、权限组件源码分析
  • 六、认证组件源码分析

一、路由组件

对于视图集ViewSetMixin,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

也就是通过路由组件帮助我们自动生成路由,它会根据URL及请求匹配对应的视图方法,而这些方法则是来自视图集,如果我们需要自定义方法来处理请求的话,后续可以搭配action装饰器实现。

SimpleRouter为每个URL添加一个斜杠后缀,可以在初始化的时候提供trailing_slash参数,并设置为False

创建router对象,并注册视图集

	'导入'
	from rest_framework.routers import SimpleRouter,DefaultRouter
	'导入的模块不是继承就是实例化'
	router = SimpleRouter() 或者DefaultRouter()  # 创建对象
	'''
	DefaultRouter会生成一个根路径/的配置项
	DefaultRouter生成的每个配置项后都可以跟上.json,直接返回json数据
	还可以显示注册过的路由以及美化的页面
	SimpleRouter和DefaultRouter用法一致,功能几乎一样
	'''


	'注册路径,可以注册多个'
	router.register('publish',views.PublishView)  # 注册路由,并选择视图函数
	'注册:第一个参数是路径,第二个参数为视图类,第三个参数起别名用得少所有这里没用'
	
	urlpatterns = []
	
	
	'把生成的路由添加到urlpatterns路由列表中,有两种方式:'
	# 将生成的路由加入到Django需要调用的路由列表内
	'方式一:直接添加+='
		urlpatterns += router.urls
	'方式二:直接添加到urlpatterns里面使用include'
		from django.urls import path,include
		urlpatterns = [path('',include(router.urls))]
	

def register(self, prefix, viewset, basename=None):

注册参数说明:

  • prefix:路由的前缀
  • viewset:视图集(内部必须继承了ViewSetMixin类)
  • basename:路由的别名

上序代码会生成如下路由:

	path('publish/',views.PublishView.as_view()),
    path('publish/<int:pk>',views.PublishView.as_view()),

	''''
		^publish/$' [name='publish-list
		^publish/(?P<pk>[^/.]+)/$' [name='publish-detail']
	'''

每个路由对应的接口功能

	publish/:get请求的话则会执行视图集里面的list方法
	publish/:post请求的话则会执行视图集里面的create方法

	publish/<int:pk>/:get请求执行视图集里面的retrieve方法
	publish/<int:pk>/:put请求执行视图集里面的update方法
	publish/<int:pk>/:delete请求执行视图集里面的destroy方法

实际展示
视图类

	from rest_framework.viewsets import ModelViewSet
	'必须是继承了ViewSetMixin类的视图类才能使用这种自动生成路由的方法'
	class PublishView(ModelViewSet):
	    queryset = models.Publish.objects.all()
	    serializer_class = PublishSerializer

路由

	from rest_framework.routers import SimpleRouter
	router = SimpleRouter()
	router.register('publish',views.PublishView)
	urlpatterns = []
	urlpatterns += router.urls

此时上面代码就可以自动生成路由了,完成了增、删、改、查(一条或多条数据)的接口了,但是不包括在视图集里面自定义的方法。

如果要给我们自定义的方法也加上路由,那么则需要使用action装饰器来声明。


SimpleRouter生成URL的方式
在这里插入图片描述


DefaultRouter生成URL的方式
在这里插入图片描述


action装饰器

在视图集中,如果想要让Router自动帮助我们为自定义的方法生成路由信息,需要使用rest_framework.decorators.action装饰器。

使用action装饰器的方法名会作为路由的后缀,例如:

	/publish/使用action装饰器的方法名/

并且action装饰器会接收两个参数:

  • methods:声明该action对应的请求方式,列表传递:['get','post']表示该路由get请求与post请求。
  • detail:声明该action的路由是否与单一资源(就是单条数据)对应,如果需要的话设置True。
	/publish/<int:pk>/使用action装饰器的方法名/
	
	True:表示路径格式是:/publish/pk/action方法名/
	False:表示路径格式是:/publish/action方法名/
  • url_path:控制生成的/使用action装饰器的方法名/后面的路径是什么,如果不写默认以方法名
  • url_name:别名,用于反向解析

实际案例
视图类

	from rest_framework.viewsets import ModelViewSet
	from rest_framework.response import Response
	from rest_framework.decorators import action
	class PublishView(ModelViewSet):
	    queryset = models.Publish.objects.all()
	    serializer_class = PublishSerializer
	
	    @action(methods=['post'], detail=False)
	    def login(self,request):
	        return Response({'message':'登录成功'})
	
	    @action(methods=['get'],detail=True)
	    def test(self,request,pk):
	        return Response({'message':'测试成功'})

效果展示
在这里插入图片描述
在这里插入图片描述
此时可以从浏览器上看到自动生成的路由

	api/v1/ ^publish/$ [name='publish-list']
	api/v1/ ^publish/login/$ [name='publish-login']
	api/v1/ ^publish/(?P<pk>[^/.]+)/$ [name='publish-detail']
	api/v1/ ^publish/(?P<pk>[^/.]+)/test/$ [name='publish-test']

它使用的是正则来匹配,中间使用了有名分组,以关键字:pk=xx的形式传给视图。


二、认证组件(Authentication)

在DRF中,我们要进行登录认证的话需要使用DRF内部的认证组件,为什么不用auth组件?因为DRF重新封装了request方法,而当我们使用原来reqeust.user时,则会调用_authenticate方法,然后在调用我们编写的认证类里面的authenticate方法进行认证。

开启认证有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK={
	    "DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth"]
	    # value值是我们认证组件类在当前项目的路径
	}

局部开启:在视图类里面指定认证类

	'导入登录认证类'
	from .auth import LoginAuth
	authentication_classes = [test.LoginAuth, ]
	# 认证可以有多个,在调用_authenticate方法时会将列表里面类实例成对象,然后执行对象里面的authenticate方法。
	# 执行顺序从前至后,如果某个对象返回了正确结果则后面对象不会执行。

	'如果全局认证了但是又不想让某一个不认证,需要再视图类里面写入authenticate_classes = []清空即可'

登录认证类

	from rest_framework.authentication import BaseAuthentication
	from . import models
	from rest_framework.exceptions import AuthenticationFailed
	'''
	通过认证类完成,使用步骤
		1 写一个认证类,继承BaseAuthentication
	    2 重写authenticate方法,在内部做认证
	    3 如果认证通过,返回2个值
	    4 认证不通过抛AuthenticationFailed异常
	    5 只要返回了两个值,在后续的request.user 就是当前登录用户
	'''
	
	class LoginAuth(BaseAuthentication):
	    def authenticate(self, request):  重写authenticate方法,做内部认证
	        # 完成对用户的校验
	        # 当次请求的request
	        token = request.query_params.get('token')  获取token
	        user_token = models.UserToken.objects.filter(token=token).first()
	        if user_token:
	            user = user_token.user  # 如果通过认证返回两个值,不通过则抛异常
	            'return后,在后续的视图类的方法中,就可以通过reqeust.user取到当前登录的用户'
	            '如果不按照这个规则来写,后续视图类的request.user是取不到当前登录用户'
	            return user,user_token
				'质押返回了两个值,在后续的request.user就是当前登录用户'
	        else:
	            raise AuthenticationFailed('您没有登录!')

三、权限组件(Permissions)

权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

  • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
  • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

开启权限有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK = {
	    'DEFAULT_PERMISSION_CLASSES': [
	        'app01.permission.CommonPermission',
	    ],
	}

	'注意,不要再配置文件乱导入不使用的东西,否则没有加载过就使用会直接报错。'

局部开启:在视图类里面指定权限类

	'导入权限类'
	from .permission import CommonPermission
	permission_classes = [CommonPermission]
	'如果全局设置权限了但是又不想让某一个不设置权限,需要再视图类里面写入permission_classes = []清空即可'

补充

	如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部
	-'.has_permission(self,request,view)'
	是否可以访问视图,view表示当前视图对象

	-'.has_object_permission(self,request,view,obj)'
	是否可以访问数据对象,view表示当前视图,obj为数据对象

权限类的定义

	'models.py定义的用户表'
	class User(models.Model):
	    username = models.CharField(max_length=64)
	    password = models.CharField(max_length=64)
	    user_type = models.IntegerField(default=1, choices=((1, '普通用户'), (2, '管理员'), (3, '超级管理员')))


	from rest_framework.permissions import BasePermission
	'''
	权限类其实跟认证类一样只需要继承类修改方法
	使用步骤
	1 写一个类,继承BasePermission
	2 重写has_permission方法(也可以不继承BasePermission,但是重写这个方法,一样有用,因为python是鸭子类型)
	3 在方法中校验用户是否有权限(request.user就是当前登录用户)
	4 如果有权限,就返回True,没有权限,返回False
	5 self.message 是显示给前端的中文提示信息
	'''
	
	'我这里创建是一个只有超级管理员才能访问其他人都不能访问的例子'
	class CommonPermission(BasePermission):   # 随意定义一个类继承BasePermission
	    def has_permission(self, request, view):  # 重写has_permission方法
	    	'''
	    	到了这里,正常步骤应该登录完了,可以使用reqeust.user来查看当前登录用户
	    	然后拿到用户后判断用户是否有权限,去用户表中查看用户类型字段user_type,然后根据类型判断是否有权限
	    	 -ACL:访问控制列表
	        -rbac:公司内部系统,基于角色的访问控制
	        -abac:rbac升级版,加了属性认证
	    	'''
	        try:  # 这里进行异常捕捉,因为有可能有匿名用户所以需要进行捕捉
	            user_type = request.user.user_type  
	            print(f"用户:{request.user.get_user_type_display()}")
	            print(f"编号:{user_type}")
	            if user_type == 3: # 获取用户的管理员信息,如果有权限返回True,否则False
	                return True
	            else:
	            	'报错信息渲染,这里的reqeust.user.get_user_type_display()是返回这个字段的choice对应的文字'
	                self.message = f"你是{request.user.get_user_type_display()}。没有权限进行操作!"
	                return False
	        except Exception as e:  # 当是匿名用户或者说是没有登录的用户,走这里
	            # print(request.path) 
	            '这里的判断是为了给登录和注册页进行解除设限'
	            if 'login' in request.path: # 获取
	                return True
	            elif 'register' in request.path:
	                return True
	                
	            '渲染报错信息渲染'
	            self.message = "您没有登录,没有权限进行操作!"
	            return False

内置权限类

当我们通过create_user或者createsuperuser也可以具备权限,DRF提供了以下权限类。

	from rest_framework.permissions import AllowAny,IsAuthenticated,IsAdminUser,IsAuthenticatedOrReadOnly
	- AllowAny	允许所有用户
	- IsAuthenticated	仅通过认证的用户
	- IsAdminUser	仅管理员用户
	- IsAuthenticatedOrReadOnly	以及登录认证的用户可以对数据进行增删改查操作,没有登录认证的只能查看数据

我们可以根据哪个视图的需要来进行引入。
全局使用:这就表示所有视图都只能通过认证的用户访问

	REST_FRAMEWORK = {
	    'DEFAULT_PERMISSION_CLASSES': [
	        'rest_framework.permissions.IsAuthenticated',
	    ],
	}

如果需要某几个视图不想使用这种效果的话,则可以进行局部禁用

	permission_classes = [] # 设置空即可,或者指定别的权限类

如果未指定的话,则使用DRF默认的

	REST_FRAMEWORK = {
		'DEFAULT_PERMISSION_CLASSES': [
		   'rest_framework.permissions.AllowAny',
		]
	}

四、频率组件(Throttling)

我们也可以称其为:限流。其主要作用:

  • 可以对接口访问的次数进行限制,以减轻服务器压力
  • 一般用于付费购买次数,投票等场景使用。

开启频率有两种方法:

  • 局部开启
  • 全局开启

全局开启方式:在settings.py文件里面进行DRF配置

	REST_FRAMEWORK = {
	    'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],
	}
	'注意,不要再配置文件乱导入不使用的东西,否则没有加载过就使用会直接报错。'

局部开启:在视图类里面指定权限类

	'导入权限类'
	from .throttling import CommonThrottle
	throttle_classes = [CommonThrottle]
	'如果全局设置权限了但是又不想让某一个不设置权限,需要再视图类里面写入permission_classes = []清空即可'

频率类的定义

	from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
	from . import models
	
	'''
	使用步骤:
		1.写一个类继承SimleRateThrottle
		2.重写get_cache_key方法,返回一个唯一的字符串,会以这个字符串做频率限制
		3.有两种写法
			3.1 写一个类属性 scope='随意命名',使用这个方法的必须要与配置文件中定义使用
				配置文件中写
				REST_FRAMEWORK = {
				    'DEFAULT_THROTTLE_RATES': {
				    	'key要跟类中的scop定义的名字对应': '5/m',
				    },
				    # 表示该接口一分钟只能被访问5次,key值就是我们频率类里面的scope属性值
				        这个字典后面value值里面的/前面的是访问次数,后面是超过次数后等待的时间,可以根据
				        下面参数来进行选择即可。
				        {'s':1,'m':60,'h':3600,'d':86400}  # 都是使用秒来计算
				        我们也可以直接使用英文单词来:秒:second,分:minute,时:hour,天:day
				}
			3.2 写一个类属性 rate = '5/minute' 这种写法就无需配合配置文件中写了,相当于直接整合了
	'''
	
	'这里我以一个登录用户id进行限制一分钟访问三次'
	class CommonThrottle(SimpleRateThrottle):
	    rate = '3/minute'  # second minute hour day
	    
	    def get_cache_key(self, request, view):
	        user = request.user
	        obj = models.User.objects.filter(username=user.username).first()

			'''
			返回什么,频率就可以做什么限制
			比如也可以通过IP地址进行限制,ip = request.META.get('REMOTE_ADDR')
			'''
	        return obj.pk  # ip

在settings中使用匿名用户、普通用户的限制

	REST_FRAMEWORK = {
	    'DEFAULT_THROTTLE_CLASSES': (
	        'rest_framework.throttling.AnonRateThrottle', # 匿名用户限流
	        'rest_framework.throttling.UserRateThrottle', # 普通用户限流
	    ),
	    'DEFAULT_THROTTLE_RATES': {
	        'anon': '3/m', # 设置匿名用户每分钟只能访问3次
	        'user': '5/m', # 设置普通用户每分钟只能访问5次
	    }
	}

五、权限组件源码分析

	'''
	我们知道在DRF的APIView中有三大认证是在执行视图类的方法之前就执行了三大认证,
	也就是APIView中的dispatch方法中的self.initial。在之前几篇DRF博客中,以及介绍解读过APIView的源码了
	所以这里我就不重头开始解读了,直接从dispatch里面开始了
	'''
    def dispatch(self, request, *args, **kwargs):
        try:
        	'就是在这里执行了三大认证:认证、权限、频率'
            self.initial(request, *args, **kwargs)

            '执行视图类的方法开始'
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            response = handler(request, *args, **kwargs)
            '执行视图类的方法结束'

        except Exception as exc:  全局异常捕捉
            response = self.handle_exception(exc)
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
	
	'''
	我们找到了这个dispatch里面执行三大认证的地方后,
	我们知道,这个self是视图类的对象,而视图类是继承了APIView这个类
	所以我们先去APIView这个类中找一下有没有这个initial的方法,结果是有的
	'''
	找到了APIView里的initial
    def initial(self, request, *args, **kwargs):
       self.perform_authentication(request) # 认证组件
       self.check_permissions(request) # 权限组件
       self.check_throttles(request) # 频率组件
	
	'因为我们这里是分析权限组件的,所以在这里只看一下权限的,跟上面一样,这个self还是视图类的对象'
	在APIView里面找到了check_permissions方法
	# 检查请求是否具有所需的权限
    def check_permissions(self, request):
       # 遍历视图或视图集的权限类列表
       '这里的self还是视图类的对象,然后我们又得去APIView里面找看有没有get_permissions方法'
       '''
		def get_permissions(self):
	       	return [permission() for permission in self.permission_classes]
	       	在这个get_permissions里面直接返回了一个列表生成式,我们得去看看这个self.permission_class是什么
	       	permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
	       	从上面点击查看到的可以得知,self.permission_class就是咱们配置在视图类中的列表,
	       	里面是一个个权限类,并且没加括号执行。
	       	然后我们可以知道它每次从我们自己的视图类的permission_class列表中拿出一个值出来
	       	所以这里的返回值就是每次拿到一个值然后加括号执行,其实就是我们配置的一个个权限类的对象
		'''
  所以这里self.get_permissions()就是拿到一个个我们配置的权限类的对象的列表,然后在这里又进行循环一个个拿出
       for permission in self.get_permissions(): 所以这里的permission就是我们写的一个个的权限类的对象
       	   # 调用每个权限类的 has_permission 方法进行权限检查
       	   '''
       	   这里看到has_permission,这个就是为什么我们需要再权限类中重写这个方法,因为在这里它在调用它
       	   并且传入了两个参数,这个request就是APIView包装后的新的request,而这个self它还是我们视图类的对象
       	   因为还是在APIView中。这就是为什么我们在权限类中重写has_permission方法括号中加入了一个view参数,
       	   就是接收了这个的self也就是视图类对象。
       	   所以我们这个权限类中的view其实就可以直接拿到view.request,也可以直接拿到view.action等参数
       	   '''
           if not permission.has_permission(request, self):
           '而这里在权限类中has_permission方法如果返回值是True就不会执行这里的代码,反之就会走这里'
               # 如果权限检查失败,调用 permission_denied 方法,拒绝访问
               self.permission_denied(
               '这里的self还是视图类的对象,当执行了这个permission_denied就是说明没有权限'
			   '''
			   这里注意一个点,如果配置了多个权限类,如果第一个权限类就没过,
			   就不会执行后面的权限类,所以得把想要过的放最前面
			   '''
                   request,
                   # 获取权限类中可能定义的消息和代码
                   message=getattr(permission, 'message', None),
                   '这里的message和code都是从我们权限类的对象中反射过来的'
                   code=getattr(permission, 'code', None)
               )

	'在这里我们还可以看看,这个permission_denied,它还是在APIView中'
    def permission_denied(self, request, message=None, code=None):
       if request.authenticators and not request.successful_authenticator:
           raise exceptions.NotAuthenticated()
       raise exceptions.PermissionDenied(detail=message, code=code)
       '''
       可以看到它执行抛了异常,因为抛了异常,最后会被APIView中的全局异常捕捉到
       并且把上面的message和code都传入过去message会放在响应体中,code会放在响应状态码中
       '''

总结:

	权限类源码的执行流程:
	1.先去视图类继承的APIView中的dispatch方法中执行self.initial方法
	2.然后又执行APIView的initial方法中的self.check_permissions(request)
	3.然后从里面取出配置在视图类中的权限类,实例化得到对象。
	4.然后for循环一个个执行对象的has_permission方法(重写的方法),如果返回False就直接结束,不再往下执行
	  权限就认证通过
	
	'小细节'
	1.为什么写一个类继承BasePermission,重写has_permission方法
		-也可以不继承这个类,只重写这个方法也可以(因为python是鸭子类型)
	2.权限类中 self.message  会返回给前端
	3.局部配置:放在视图类中:permission_classes = [权限类名]
	4.全局配置,配置在配置文件中也可以,那么视图类中就没有
		-如果视图类上不配做权限类,permission_classes = [],
		 会默认使用配置文件的api_settings.DEFAULT_PERMISSION_CLASSES
		-执行的顺序:优先使用项目配置文件----->其次使用drf内配置文件

六、认证组件源码分析

	'因为也是继承了APIView,从上面权限组件源码分析中我们知道在它的dispatch方法中有一个initial方法'
	'里面也有一个认证组件的'
		
    def initial(self, request, *args, **kwargs):
       self.perform_authentication(request) # 认证组件
       self.check_permissions(request) # 权限组件
       self.check_throttles(request) # 频率组件
    '因为我们这里是分析只分析认证组件的,然后self还是视图类的对象'
	在APIView里面找到了perform_authentication方法
    def perform_authentication(self, request):
      '''
      可以看到里面只写了一句代码,因为这里还是APIView所以这里的self还是视图类的,
      这里的reqeust就是APIView包装的新的request。
      '''
       request.user
       '这里可以看到request.user,可以会觉得它是一个属性,但是其实它是一个方法,是伪装成数据属性的'
       
   '这样我们就得回到APIView源码中找了,因为我们这个新的reqeust是在Request中,所以我们得去看它了'
    我们直接在视图中导入这个然后找到这个user位置:from rest_framework.request import Request
    @property
    def user(self):  这里的self就是Request的对象,因为它并没有继承任何一个类。所以就是它自己的对象
	    if not hasattr(self, '_user'):
	    '然后这里是看有没有这个_user,但是我们确实是没有,所以是False,但是又if了not所以变成True'
	        with wrap_attributeerrors():  # 上下文管理器
	            self._authenticate()  所以会执行这一句
	    return self._user

	'sel_authenticate()这里的self就是Resquest对象,所以我们找找Resquest中有没有这个方法'
    def _authenticate(self):
       '''
       这里循环跟权限组件那块差不多
       self.authenticators,就是我们配置在视图类中认证类的一个个对象,放在列表中
       所以这里循环出来的authenticator就是一个个我们配置的认证类对象
       '''
       for authenticator in self.authenticators:
       此处对上面几句的解释
       '''
       这个self还是Resquest对象,我们在Resquest中找authenticators,
       而它不是一个方法,而是一个属性,所以我们直接按住Ctrl+鼠标左键点击跳转即可
       def __init__(self, request, parsers=None, authenticators=None,
       negotiator=None, parser_context=None):
       		self.authenticators = authenticators or ()
       从我们点击跳转找到的我们可以看到这个是Resquest类实例化后得到的对象的初始化方法,会把对象的
       authenticators传入给了,self.authenticators对象,所以我们在类实例化调用这个初始化方法是什么时候
       实例化类的,我们得去APIView中找找,在我们之前博客中有写过APIView的源码分析中知道,在它的dispatch中
       request = self.initialize_request(request, *args, **kwargs)这里实例化得到对象了,所以我们去看看
       
          def initialize_request(self, request, *args, **kwargs):
	       return Request(
	           request,
	           parsers=self.get_parsers(),
	           authenticators=self.get_authenticators(),
	           negotiator=self.get_content_negotiator(),
	           parser_context=parser_context
	       )
	       从上面代码中可以看到返回了authenticators=self.get_authenticators(),
	       这里的self又是谁?现在是在APIView中,所以这里的self是视图类的对象
	       然后直接跳转到这个self.get_authenticators()
	           def get_authenticators(self):
		        return [auth() for auth in self.authentication_classes]
		        self.self.authentication_classes,self就是视图类的对象,
		        而authentication_classes就是在视图类中配置的认证类中的一个个对象,它是一个列表
		        
       '''
           try:
           	   '''
           	   因为上面我们知道了authenticator就是我们配置的一个个认证类,
           	   而这里的authenticate就是我们在认证类中重写的方法,因为在这里调用它了。
           	   而这里的self就还是APIView包装的新的Resquest对象,所以在认证类中重写这个方法后面接收了它
           	   然后执行认证类的这个方法,后返回值就赋值给了user_auth_tuple
           	   这里在我们认证类的这个方法中返回了两个值:
           	   		第一个是当前登录用户,第二个的token,只走这一个认证类,后面的不再走了
           	   		也可以返回None,这样就会继续执行下一个认证类
           	   '''
               user_auth_tuple = authenticator.authenticate(self)
               
           '''
           如果这里没有重写这个方法就抛出异常,它并没有捕获AuthenticationFailed,而是APIException
           但是AuthenticationFailed是继承了APIException。所以我们在认证类抛出异常使用AuthenticationFailed
           '''
           except exceptions.APIException:
               self._not_authenticated()
               raise
			
		   '这里如果user_auth_tuple不是空的话,就走这里,就是正常返回了认证类方法的两个值'
           if user_auth_tuple is not None:
           	   
               self._authenticator = authenticator
              '''
              这里的self就还是Resquest的对象,并且使用了解压赋值,然后把user_auth_tuple的两个值分别赋值
              这就是为什么后续在视图类中,reqeust.user就是当前登录的用户,request.auth就是另一个参数
              当认证类没有返回值,那么这里就是空,如果有第二个认知类那么就会进行第二次循环,如果有返回值
              就解压赋值完毕后,直接结束了。
              '''
               self.user, self.auth = user_auth_tuple
               '''
               所以这里我们可以知道,在视图类中配置认证类是可以配置多个的,
               如果第一个认知类有返回值就不会再执行第二个认证类,如果没有返回值,则会执行第二个认证类。
           	   而返回的两个值,第一个给了reqeust.user,第二个给了reqeust.auth,这样在后续视图类中就可以取到
               '''
               return
       self._not_authenticated()

总结

	1.在认证类中,重写authenticate方法(不重写就无法调用)
	2.为什么校验失败抛异常,因为我们写了AuthenticationFailed,
		又AuthenticationFailed是继承了APIException所以能捕获
	3.通过认证就会返回两个值或者None
		(如果没有返回值就会执行下一个认证类,或者没有在后续视图类中request.user和reqeust.auth就拿不到值)
	4.视图类上局部配置和配置文件全局配置跟权限类的一模一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1338850.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Swift 周报 第四十二期

文章目录 前言新闻和社区苹果 CEO 库克透露接班计划&#xff0c;希望继任者来自公司内部消息称苹果自研 5G 调制解调器开发再“难产”&#xff0c;将推迟到 2026 年 提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组整理周报的第四十二期&…

K8S异常处理

一、概述 1、k8s有时候会报错The connection to the server ip:6443 was refused - did you specify the right host or port &#xff0c;本文档提供几种可能产生该报错的原因和排障思路。 二、发现问题 使用任意Kubectl 命令会报错&#xff1a;The connection to the serv…

uniapp Vue3 日历 可签到 跳转

上干货 <template><view class"zong"><view><view class"top"><!-- 上个月 --><view class"sgy" click"sgy">◀</view><view class"nianyue">{{ year }}年{{ month 1 }}…

Python - 深夜数据结构与算法之 Divide Conquer Backtrack

目录 一.引言 二.分治与回溯简介 1.Divide & Conquer 分治 2.BackTrack 回溯 三.经典算法实战 1.Combination-Of-Phone [17] 2.Permutations [46] 3.Permutations-2 [47] 4.Pow-X [50] 5.N-Queen [51] 6.Combinations [78] 7.Sub-Sets [78] 8.Majority-Elemen…

模式识别与机器学习-无监督学习-聚类

无监督学习-聚类 监督学习&无监督学习K-meansK-means聚类的优点&#xff1a;K-means的局限性&#xff1a;解决方案&#xff1a; 高斯混合模型&#xff08;Gaussian Mixture Models&#xff0c;GMM&#xff09;多维高斯分布的概率密度函数&#xff1a;高斯混合模型&#xff…

DBAPI个人版如何升级到企业版

安装好企业版软件&#xff0c;并启动 注意要新建mysql数据库&#xff0c;执行新版本的ddl_mysql.sql脚本 在旧版本系统中分别导出数据源、分组、API&#xff0c;得到3个json文件 注意全选所有的数据导出 在新版本系统中导入数据源 在新版本系统中导入分组 进入分组管理菜单&…

FART12刷机脱壳记录笔记

其他脱壳笔记&#xff1a; https://codeooo.blog.csdn.net/article/details/126891503 fart12 脱壳系统 可以脱邦邦 爱加密 企业壳 等&#xff1b; 寒冰大佬的脱壳王 本文记录下刷机过程&#xff0c;方便以后查看使用。 adb授权和ome锁要开着 代表锁是开着状态 如果出现&a…

鸿蒙原生应用/元服务开发-Serverless账户验证码的问题

在应用/元服务早期使用过程中&#xff0c;-Serverless账户验证码的格式是[AGC][应用/元服务名称]&#xff0c;如下图。 但是&#xff0c;在最近&#xff0c;[应用/元服务]名称直接变成了【default】,用户收到这种验证码后&#xff0c;心里存有疑虑的&#xff0c;这是哪里配置…

实习知识整理11:确认订单并将订单的相关信息插入用户订单表和订单详情表

用户订单表&#xff1a; 订单详情表&#xff1a; 思路分析&#xff1a;首先我们需要知道当点击了确认订单按钮后&#xff0c;需要向后端传递哪些数据&#xff0c;先看用户订单表&#xff1a;ORDER_ID是不需要传的&#xff0c;这个可以在后台生成就行了&#xff1b;USER_ID是需要…

【赠书第13期】边缘计算系统设计与实践

文章目录 前言 1 硬件架构设计 2 软件框架设计 3 网络结构设计 4 安全性、可扩展性和性能优化 5 推荐图书 6 粉丝福利 前言 边缘计算是一种新兴的计算模式&#xff0c;它将计算资源推向网络边缘&#xff0c;以更好地满足实时性、低延迟和大规模设备连接的需求。边缘计算…

腾讯开源AppAgent,手机的大模型智能代理

腾讯研究团队开源了一款基于大语言模型的&#xff0c;用于手机端执行复杂任务的多模态智能代理框架——AppAgent。 据悉&#xff0c;AppAgent的功能与AutoGPT等智能代理类似&#xff0c;不依赖于操作系统的后台访问,而是通过UI界面进行点击、滑动等拟人化操作&#xff0c;与Ap…

继电保护测试仪的这4点用途和6点功能你知道几个?

众所周知&#xff0c;继电保护系统是电力系统中至关重要的组成部分。当电路出现故障时&#xff0c;它可以快速准确地切除故障部分&#xff0c;以确保电力系统的安全稳定运行。然后&#xff0c;为了提前发现和保证继电保护系统的故障和问题&#xff0c;通常需要使用继电保护测试…

嵌入式面试准备

题目都摘于网上 嵌入式系统中经常要用到无限循环&#xff0c;如何用C编写死循环 while(1){}或者for(;&#x1f609; 内存分区 代码区&#xff0c;全局区&#xff08;全局变量&#xff0c;静态变量&#xff0c;以及常量&#xff09;&#xff0c;栈区&#xff0c;堆区 const关键…

企业知识库:成为优秀企业的必备系统

导语&#xff1a; 在当今竞争激烈的商业环境中&#xff0c;企业需要不断创新和提高团队的协作效率&#xff0c;以保持竞争优势。而构建一个优秀的企业知识库系统已经成为众多企业必备的系统之一。本文将介绍企业知识库的定义、作用以及如何搭建一个完整有效的企业知识库。 什么…

基于MATLAB的正态分布与卡方分布(附完整代码与例题)

目录 一. 理论部分 二. MATLAB所使用的函数介绍 2.1 概率密度函数 2.2 概率分布函数 2.3 逆概率分布函数 三. 例题与代码 例题1 例题2 例题3 例题4 一. 理论部分 将连续随机变量的概率密度函数记为&#xff0c;既然跟概率相关&#xff0c;那必然满足两个重要的性质&a…

智能酒精壁炉历史轨迹:文化传统与现代融合的取暖方式

智能酒精壁炉作为一种取暖装置&#xff0c;承载着丰富的历史和文化传统。深入了解其在不同文化中的演变过程&#xff0c;以及如何成为现代家庭的取暖方式&#xff0c;可以了解智能酒精壁炉在历史中的发展轨迹。 古希腊和古罗马时期&#xff0c;人们使用酒精和其他可燃性液体作…

猫冻干什么牌子口碑好?专业人士分享口碑好的五款冻干猫粮牌子

近几年&#xff0c;冻干猫粮在宠物圈内非常流行&#xff0c;许多品牌都推出了冻干猫粮。在所有的猫食品中&#xff0c;冻干无疑是最具营养、动物蛋白含量最高的食品之一。冻干作为现在宠物圈最火的猫食品&#xff0c;受到了众多猫友们的喜爱和追捧。但有些铲屎官在选择冻干猫粮…

手动创建idea SpringBoot 项目

步骤一&#xff1a; 步骤二&#xff1a; 选择Spring initializer -> Project SDK 选择自己的JDK版本 ->Next 步骤三&#xff1a; Maven POM ->Next 步骤四&#xff1a; 根据JDK版本选择Spring Boot版本 11版本及以上JDK建议选用3.2版本&#xff0c;JDK为11版本…

rosdep init/update失败(转载)

sudo rosdep init rosdep update 如果你直接成功了&#xff0c;可直接跳过当我没说&#xff08;不过90%的几率你都会失败的啦&#xff09; 由于http://raw.githubusercontent.com这个网址墙的很厉害&#xff0c;大概率你是成功不了的&#xff0c;这里推荐一种本地化安装的方法…

Docker - 镜像 | 容器 | 数据卷 日常开发常用指令 + 演示(一文通关)

目录 Docker 开发常用指令汇总 辅助命令 docker version docker info docker --help 镜像命令 查看镜像信息 下载镜像 搜索镜像 删除镜像 容器命令 查看运行中的容器 运行容器 停止、启动、重启、暂停、恢复容器 杀死容器 删除容器 查看容器日志 进入容器内部…