drf07-三大权限认证-三大源码-鸭子类型

1 drf路由的使用

-路由有三种写法
	-视图类.as_view()
    -视图类.as_view({'get':'list'})
    -自动生成路由
    	-导入--实例化--注册--加入到urlpatterns
        -类有两个:SimpleRouter, DefaultRouter
        -加入到urlpatterns的两种方式:列表加操作,include
-路由的第二种和第三种写法,视图类必须继承ViewSetMixin---》重写了类方法as_view
-要自动生成:其实自动生成的是定死的{'get':'list','post':'create','delete':destroy,put:update,get:retrieve}
-如果你完全自动生成路由,视图类必须有:list,create....
-可以继承ViewSetMixin+GenericAPIView+5个视图扩展类
-继承ViewSetMixin+9个视图子类

-视图类中得其他方法必须使用action装饰器来装饰,才能自动生成路由
/user/login
@action(methods=['post','get'],detail=False,url_path='login')

2 视图类

-APIView:所有东西都需要自己写,get,post。。。。
-GenericAPIView:(以后要跟表模型打交道就继承它)
	-必须要配置两个类属性:要序列化的数据,序列化类
    -get,post。。。
    -self.get_queryset()
    -self.get_serializer()
    -self.get_object()
-5个视图扩展类:要配合GenericAPIView就可以完成5个接口的写法
    ListModelMixin:list
    CreateModelMixin:create
    DestroyModelMixin:destroy
    RetrieveModelMixin:retrieve
    UpdateModelMixin:update
-9个视图子类:GenericAPIView+5个视图扩展类的组合+写个请求方式的某个方法
	ListAPIView:get
    CreateAPIView:post
    
    UpdateAPIView:put
    RetrieveAPIView:get
   	DestroyAPIView :delete
    
    ListCreateAPIView:get,post
    
    RetrieveUpdateDestroyAPIView:put,get,delete
    RetrieveDestroyAPIView:get,delete
    RetrieveUpdateAPIView:get,put

-视图集
-ViewSetMixin:路由写法变成了第二种或第三种
-ViewSet:ViewSetMixin+APIView
-GenericViewSet:ViewSetMixin+GenericAPIView
-ModelViewSet:GenericViewSet+5个视图扩展类
-ReadOnlyModelViewSet:GenericViewSet+2个视图扩展类

-如果不跟数据库(表模型)打交道:就继承APIView
-如果想自动生成路由(路由写法变了),就继承ViewSetMixin

登录接口

-表模型:User:用户信息,UserToken:用户登录信息
-用户向 /user/login/ 发送post请求,携带用户名密码---》自动生成路由+action装饰器
-用户登录了要有记录,只要登录成功,就在UserToken表中记录一下
	-如果之前有过记录,就要更新,如果没有记录,就是新增
-随机字符串的生成:uuid
-登录成功返回给前端{code:100,msg:登录成功,token:asdfasfas}

验证用户是否登录

-写一个认证类:继承BaseAuthentication
-重写def authenticate(self, request)方法
-在方法内部判断用户是否登录
	-自己定的规则,用户携带token在哪
    -如果token放在了请求头中,应该从哪取?---》request.META 
    	-http请求头的数据从request.META中取
        -统一取:HTTP_请求头大写
    -通过token判断用户是否登录:表中查,能查到就是登录了,查不到就是没登录
    -如果登录了返回两个值,一个是当前登录用户,一个是token
    -如果没登录,直接抛AuthenticationFailed

-认证类写好,使用
-局部使用:视图类中
-全局使用:配置文件中
-局部禁用:视图类中设置为空列表

drf 三大认证

1.权限类使用

#认证:校验用户是否登录,登录认证
#用户登录后,某个接口可能只有超级管理员才能访问,普通用户不能访问
#book所有接口,必须登录,而且是超级管理员才能访问

1.用户权限类

使用步骤

第一步:写一个类,继承BasePermission

第二步:重写has_permission方法

第三步:在方法中校验用户是否有权限(request.user就是当前登录用户)

第四步: 如果有权限,返回True,没有权限返回False

第五步:self.message 返回给前端的提示信息,比如,你的用户等级不够。

第六步: 局部使用,全局使用,局部禁用

from rest_framework.permission import BasePermission
class UserTypePermission(BasePermission):
	def has_permission(self,request,view):
	#只有超级管理员有权限
	if request.user.user_type==1:
		return True   #有权限
	else:
		#self.message = '普通用户没有权限'  这个是返回给前端的提示信息
		#使用了choice 后,user.user_type 拿到的是数字类型,变成字符串user.get_user_type_display()
		#self.message = '您是:%用户,您的等级还不够哦'%request.user.get_user_type_display()
		return False  #没有权限

2.访问频率类

无论是否登录,都要限制访问的频率,比如一分钟三次

​使用步骤

第一步: 写一个类,继承SimpleRateThrottle

第二步: 重写get_cache_key,返回唯一的字符串,会以这个字符串做频率限制

第三步:写一个类属性 scop='字段随意',必须要跟配置文件对象

第四步:配置文件中写

  'DEFAULT_THROTTLE_RATES': {
    '随意写': '3/m'  # 3/h  3/s  3/d
	}

第五步:局部配置,全局配置,局部禁用

from rest_framework.throttling import BaseThrottle, SimpleRateThrottle
class MyThrottling(SimpleRateThrottle):  # 我们继承SimpleRateThrottle去写,而不是继承BaseThrottle去写
    # 类属性,这个类属性可以随意命名,但要跟配置文件对应
    scope = 'luffy'
    def get_cache_key(self, request, view):
        # 返回什么,频率就以什么做限制
        # 可以通过用户id限制
        # 可以通过ip地址限制
        return request.META.get('REMOTE_ADDR')
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':['app01.throttling.MyThrottling'],
    'DEFAULT_THROTTLE_RATES': {
        'luffy': '3/m'
    }
}

3 认证源码分析

# 写个认证类,重写某个方法,配置在视图类上,就有认证了---》认证类加了,在视图类的方法中,request.user就是当前登录用户---》猜认证类的执行,是在在视图类的方法之前执行的
# 源码分析:
	-之前咱们读APIView的执行流程---》包装了新的request,执行了3大认证,执行视图类的方法,处理了全局异常
    -入口:APIView的dispatch
    -APIView的dispatch的496行上下:self.initial(request, *args, **kwargs)
    -APIView的initial
    -413行上下:有三句话,分别是:认证,权限,频率
    	self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)
    -读认证类的源码---》APIView的perform_authentication(request),315行上下
    	def perform_authentication(self, request):
        	request.user  # 新的request
    -request是新的request---》Request类中找user属性(方法),是个方法包装成了数据属性
	-来到Request类中找:220行
       def user(self):
            if not hasattr(self, '_user'): # Request类的对象中反射_user
                with wrap_attributeerrors():
                    self._authenticate()  # 第一次会走这个代码
            return self._user
    -Request的self._authenticate()---》373行
        def _authenticate(self):
            for authenticator in self.authenticators: # 配置在视图类中所有的认证类的对象 
                try:
                    #(user_token.user, token)
                    user_auth_tuple = authenticator.authenticate(self) # 调用认证类对象的authenticate
                except exceptions.APIException:
                    self._not_authenticated()
                    raise

                if user_auth_tuple is not None:
                    self._authenticator = authenticator # 忽略
                    self.user, self.auth = user_auth_tuple # 解压赋值
                    return
			  # 认证类可以配置多个,但是如果有一个返回了两个值,后续的就不执行了
            self._not_authenticated()
            
            
    # 总结:认证类,要重写authenticate方法,认证通过返回两个值或None,认证不通过抛AuthenticationFailed(继承了APIException)异常

4 权限源码分析

-先读最简单的权限执行流程---》APIView的check_permissions(request),325行上下
    def check_permissions(self, request):
        for permission in self.get_permissions():
            # permission是咱们配置在视图类中权限类的对象,对象调用它的绑定方法has_permission
            # 对象调用自己的绑定方法会把自己传入(权限类的对象,request,视图类的对象)
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )
                
   -APIVIew的self.get_permissions(),273行上下
	return [permission() for permission in self.permission_classes]
   -self.permission_classes 就是咱们在视图类中配的权限类的列表
   -所以这个get_permissions返回的是 咱们在视图类中配的权限类的对象列表[UserTypePermession(),]


	# 总结:权限类源码
    	-为什么要写一个类,重写has_permission方法,有三个参数,为什么一定要return True或False,messgage可以做什么用

5 简单读频率类源码

# 源码分析:
	-之前咱们读APIView的执行流程---》包装了新的request,执行了3大认证,执行视图类的方法,处理了全局异常
    -入口:APIView的dispatch
    -APIView的dispatch的496行上下:self.initial(request, *args, **kwargs)
    -APIView的initial
    -413行上下:有三句话,分别是:认证,权限,频率
    	self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)
    -APIView的check_throttles:351上下
        def check_throttles(self, request):
            throttle_durations = []
            for throttle in self.get_throttles():
                if not throttle.allow_request(request, self):
                    throttle_durations.append(throttle.wait())
                    
                    
   -总结:要写频率类,必须重写allow_request方法,返回True(没有到频率的限制)或False(到了频率的限制)

6 鸭子类型

# 走路像鸭子,说话像鸭子,它就是鸭子

# 指的是面向对中,子类不需要显示的继承某个类,只要有某个的方法和属性,那我就属于这个类

# 假设有个鸭子类Duck类,有两个方法,run,speak方法
# 假设又有一个普通鸭子类,PDuck,如果它也是鸭子,它需要继承Duck类,只要继承了鸭子类,什么都不需要写,普通鸭子类的对象就是鸭子这种类型;如果不继承,普通鸭子类的对象就不是鸭子这种类型
#假设又有一个唐老鸭子类,TDuck,如果它也是鸭子,它需要继承Duck类,只要继承了鸭子类,什么都不需要写,唐老鸭子类的对象就是鸭子这种类型;如果不继承,唐老鸭子类的对象就不是鸭子这种类型

# python不推崇这个,它推崇鸭子类型,指的是
不需要显示的继承某个类,只要我的类中有run和speak方法,我就是鸭子这个类

# 有小问题:如果使用python鸭子类型的写法,如果方法写错了,它就不是这个类型了,会有问题
# python为了解决这个问题:
	-方式一:abc模块,装饰后,必须重写方法,不重写就报错
    -方式二:drf源码中使用的:父类中写这个方法,但没有具体实现,直接抛异常
posted @ 2022-10-09 19:05  名字长的像一只老山羊  阅读(16)  评论(0编辑  收藏  举报