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

文章目录

  • 一、路由组件
    • 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.mfbz.cn/a/274034.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python+selenium 定位到元素,无法点击的解决方法

今天小编就为大家分享一篇pythonselenium 定位到元素,无法点击的解决方法&#xff0c;具有很好的参考价值&#xff0c;希望对大家有所帮助。一起跟随小编过来看看吧 selenium.common.exceptions.WebDriverException: Message: Element is not clickable at point (234.75, 22)…

github新建仓库推送代码教学

之前一直用gitee&#xff0c;准备转到github。因为一步一步尝试。如果是新手或许文章会有帮助 点击 new 创建 拉代码 Idea 打开 复制一个 pom 文件作为 maven 管理 提交代码 不出意外的出意外&#xff0c;报错 点击authorize JetBrains 失败 分析问题 本质就是没有…

搭建一个高效的Python开发环境

“工欲善其事&#xff0c;必先利其器”&#xff0c;这里我们来搭建一套高效的 Python 开发环境&#xff0c;为后续的数据分析做准备。 关于高效作业&#xff0c;对于需要编写 Python 代码进行数据分析的工作而言&#xff0c;主要涉及两个方面。 1. 一款具备强大的自动完成和错…

如何快速获取抖音新用户/用户信息

一、快速获取抖音用户信息意味着什么&#xff1f; 抖音是一款热门的短视频社交平台&#xff0c;拥有海量用户和高度活跃的商业生态。用户逐渐增多&#xff0c;庞大的用户也意味着隐藏着庞大的市场和商机&#xff0c;用户的偏好、关注点等信息都时刻影响着商业的效益&#xff0…

推特(Twitter)蓝V

点击个人订阅 这里需要一张visa卡才可以订阅&#xff0c;点击获取 订阅成功

2024 年混合云:趋势和预测

混合云环境对于 DevOps 团队变得越来越重要&#xff0c;主要是因为它们能够弥合公共云资源的快速部署与私有云基础设施的安全和控制之间的差距。这种环境的混合为 DevOps 团队提供了灵活性和可扩展性&#xff0c;这对于大型企业中的持续集成和持续部署 (CI/CD) 至关重要。 在混…

GitHub的2FA验证问题解决工具

文章目录 前言认识2FA开源工具使用&#xff1a;AuthenticatorPro获取AuthenticatorPro的安卓APK如何使用 参考文章 前言 打开GitHub跳出来这个提示&#xff0c;需要进行验证&#xff1a; 如何解决呢&#xff1f;方案有很多&#xff0c;我们可以使用开源的一个工具&#xff1a;…

查看ios app运行日志

摘要 本文介绍了一款名为克魔助手的iOS应用日志查看工具&#xff0c;该工具可以方便地查看iPhone设备上应用和系统运行时的实时日志和奔溃日志。同时还提供了奔溃日志分析查看模块&#xff0c;可以对苹果奔溃日志进行符号化、格式化和分析&#xff0c;极大地简化了开发者的调试…

基于机器视觉工业相机的Raw图像和Bitmap图像的保存和转换(C#代码,UI界面版)

基于机器视觉工业相机的Raw图像和Bitmap图像的保存和转换&#xff08;C#代码&#xff0c;UI界面版&#xff09; 工业相机图像格式工业相机实现Raw图像和Bitmap图像的保存和转换的技术背景在相机SDK中获取图像转换图像的代码分析工业相机回调函数里保存Bitmap图像数据工业相机图…

Sectigo的OV多域名通配符证书与通配符证书

Sectigo的OV多域名通配符SSL证书和通配符SSL证书都可以同时保护多个域名记录&#xff0c;但是Sectigo的OV多域名通配符SSL证书并不是多域名SSL证书加通配符SSL证书&#xff0c;而是多个泛域名&#xff0c;并不包括泛域名的主域名。今天就随SSL盾小编了解Sectigo旗下的OV多域名通…

【AI】人工智能爆发推进器之卷积神经网络

目录 一、什么是卷积神经网络 1. 卷积层&#xff08;Convolutional Layer&#xff09; 2. 激活函数&#xff08;Activation Function&#xff09; 3. 池化层&#xff08;Pooling Layer&#xff09; 4. 全连接层&#xff08;Fully Connected Layer&#xff09; 5. 训练过程…

部署YUM软件仓库

借助于YUM软件仓库.可以完成安装、卸载、自动升级rpm软件包等任务&#xff0c;能够自动查找并解 决rpm包之间的依赖关系&#xff0c;而无须管理员逐个.手工地去安装每个rpm包&#xff0c;使管理员在维护大量Linux 服务器时更加轻松自如。.特别是在拥有大量Linux主机的本地网络中…

代码随想录27期|Python|Day27|回溯算法|39.组合总和|40.组合总和II|131.分割回文串

39. 组合总和 在Day24组合问题的模版上加上了一个“可以重复选用当前值”的选项&#xff0c;递归中调用backtracking的idx由i 1改为i&#xff1a; self.backtracking(i, path, res, candidates, target) # 起始位置变成i,可以重复使用当前的值 class Solution(object):def…

最新国内使用GPT4教程,GPT语音对话使用,Midjourney绘画,ChatFile文档对话总结+DALL-E3文生图

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

ESP8266 ESP-01/01s 工作模式与固件下载烧录接线

注意点&#xff1a; ESP8266 ESP-01与 ESP8266 ESP-01s接线类似 。本文使用的是ESP8266 ESP-01 WIFI模块&#xff0c;详细信息见如下图片。本文固件下载的是ESP8266 的MQTT固件&#xff0c;下载其它固件流程一致。本文使用的是杜邦线连接面包板来进行使用&#xff0c;与使用开发…

Bert模型from_pretrained报网络错误解决办法

问题描述&#xff1a; 服务器或者本地运行以下代码时报网络连接错误&#xff1a; from transformers import AutoTokenizermodel_checkpoint "distilbert-base-uncased" tokenizer AutoTokenizer.from_pretrained(model_checkpoint, use_fastTrue, cache_dir./cac…

【大数据HA】HAProxy实现thrift协议HMS服务的高可用-附Chatgpt协助截图

背景 之前安装了HMS(Hive metastore service)&#xff0c;独立于hive运行&#xff0c;安装部署过程见我下面列出的另一篇文章&#xff0c;需要为它建立HA高可用功能。防止在访问时出现单点故障问题。 【大数据】Docker部署HMS(Hive Metastore Service)并使用Trino访问Minio-C…

fragstats:景观指数趋势分析

作者&#xff1a;CSDN _养乐多_ 本文将介绍景观指数时间序列的趋势分析&#xff0c;包括趋势类型、斜率、截距等。以及景观指数突变分析所用的软件和 python 代码。 结果如下图所示&#xff0c; 图1 趋势分类图 图2 MK趋势分析 文章目录 一、景观指数计算二、景观指数时间序…

网络技术基础与计算思维实验教程_4.4_RIPv2配置实验

构建 放置三个型号为2811的路由器 给router0安装两个快速以太网接口 &#xff02; 同样的方法给router2安装 为1安装有一个以太网接口的模块 这样router1就有三个快速以太网接口和两个无线路由器接口了 构建两个和router0相连的以太网 构建和router2相连的以太网 构建和r…

【JavaScript】闭包机制

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…