DRF三大认证:认证、权限、频率、视图类分析

DRF三大认证:认证、权限、频率

登录接口

class User(ModelViewSet):
    queryset = models.User.objects.all()
    serializer_class = UserSerializer

    @action(methods=['POST'], detail=False)
    def login(self, request):
        name = request.data.get('name')
        password = request.data.get('password')
        user_obj = models.User.objects.filter(name=name, password=password).first()
        if user_obj:
            # 生成随机字符串 并转换成字符串
            token = str(uuid.uuid4())
            # 存随机字符串 需要判断user_token里面是否有登录信息 ,有就修改 没有新增 用到了update_or_create
            # 根据后面的参数(**kwargs) 如果有 则使用defaults修改  没有则连同前面和自己一起新增 返回一个元组(创建的对象,布尔值)
            user_token = models.UserToken.objects.update_or_create(defaults={'token':token},user=user_obj)
            # user_token = models.UserToken.objects.create(token=token,user=user_obj)
            print(user_token)
            return Response({'code': 100, 'msg': '登录成功', 'token': token})
        else:
            return Response({'code': 101, 'msg': '用户名或者密码错误'})

  1. 认证

    # 认证的使用
    	-第一步:写一个认证类,继承BaseAuthentication,重写authenticate  方法
        -第二步:在 authenticate 方法中判断用户是否登录(取出用户携带的token,去判断)
        -第三步:如果认证通过,返回两个值,如果认证不通过抛异常
        	-# 在后续的request对象中,有这两个值,第一个给了request.user(必须返回当前登录对象),第二个值给了request.auth(写什么传什么)
        -第四步:把写的认证类,配置在视图类中(跟请求和响应的配置一样),全局配置
        
        
        
    # 写一个认证类,继承BaseAuthentication
    	-鸭子类型:不需要显示的继承某个类,只要类中有共同的属性和方法,我们就是同一类
        非鸭子类型:比如 狗和猫 必须继承 动物类 他俩才是动物类
    

    1.1认证的使用

    #定义一个auth.py
    from rest_framework.authentication import BaseAuthentication
    from .models import UserToken
    from rest_framework.exceptions import AuthenticationFailed
    
    
    class LoginAuth(BaseAuthentication):
        def authenticate(self, request):
            # 请求的url里获取:request.query_params.get('token')
            # 请求头中获取:request.META.get('token')  取的时候HTTP_字段名
            # 获取客户端ip tmp=request.META.REMOTE_ADDR()
            # 请求体重获取: token=request.data.get('token')
            token = request.META.get('HTTP_TOKEN')
            user_token = UserToken.objects.filter(token=token).first()
            print(user_token)
            if user_token:
                # 用户登录了 放行
    
                return user_token.user, token
            else:
                raise AuthenticationFailed('没有登录')
    

    1.2全局配置和局部配置

    class BookView(ModelViewSet):
        #认证类局部配置
        authentication_classes = [LoginAuth]
        queryset = models.Book2.objects.all()
        serializer_class = BookSerializer
        
        
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [#全局使用 所有接口必须登录才可以访问
            'app01.auth.LoginAuth'
        ],
    }
    
  2. 权限

    # 游客,普通用户,管理员
    # 游客登录,可以操作book的所有接口,不能操作其他接口
    # 普通用户登录,可以操作book和publish的所有接口,不能操作其他的
    # 管理员,可以操作所有接口
    
    ### 权限如何使用
    	1:写一个权限类,继承BasePermission,重写has_permission  方法
        2:在 重写has_permission 方法中判断用户是否有权限(request.user.user_type)认证后才可以知道有什么权限
        3:如果有权限,返回True,如果返回False
        4:把写的权限类,配置在视图类中(跟请求和响应的配置一样),全局配置
    

    2.1权限的使用

    # 普通用户权限
    from rest_framework.permissions import BasePermission
    
    
    class CommonUser(BasePermission):
        def has_permission(self, request, view):
            # 当前登录用户,因为权限类在认证类后执行,所以一旦认证通过,request.user就是当前登录用户
            #  因为 普通用户和管理员都可以查看这个接口 所以 in [1,2]
            if request.user.user_type in [1, 2]:
                return True
            else:
                return False
    
    
    # 管理员权限
    class Administrator(BasePermission):
        def has_permission(self, request, view):
    
            if request.user.user_type in [2]:
                return True
            else:
                return False
    

    2.2权限的局部配置和全局配置

    全局配置
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
                'app01.auth.CommonUser',
                'app01.auth.Administrator',
            ],
    }
    
    局部配置
    permission_classes=[权限类名]
    
    #如果全局都设置 管理员权限
    那么 登录接口权限设置应该为空  这个接口就是谁都可以访问 登陆之后才可以确认是什么权限
    	图书接口 所有人都可以访问 应该也设置为空 
        出版社 设置成自己的权限 
    
  3. 频率

    # 限制访问次数(IP,用户id)
    # 限制同一个IP一分钟只能访问3次
    # 使用步骤
    	-第一步:写一个类,继承SimpleRateThrottle,重写get_cache_key
        -第二步:get_cache_key返回什么就以什么做限制,必须写类属性 scope='字符串'限制了
        -第三步:配置文件中配置
          'DEFAULT_THROTTLE_RATES': {
            '字符串': '3/m',  # key:ip_1m_3 对应频率类的scope属性, value: 3/m 一分钟访问3次
              # m:分钟
              # s:秒
              # h:小时
              # d:天
        	},
                
         -第四步:局部使用和全局使用
    

    3.1频率的使用

    #频率 限制ip一分钟只能访问三次
    from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
    class MyThrottling(SimpleRateThrottle):
        scope = 'ip_1_3'
        def get_cache_key(self, request, view):
            #返回什么就以什么做限制,返回的是客户端ip地址
            return  request.META.get('REMOTE_ADDR')
    #配置文件
        # Throttling 
        'DEFAULT_THROTTLE_RATES': {
            'ip_1_3': '3/m',   #key:对应频率scope属性的值   value:一分钟访问三次 3/m
        },
    

    3.2频率的全局配置和局部配置

    #全局配置频率
    'DEFAULT_THROTTLE_CLASSES': ['app01.auth.MyThrottling'],
        
    #局部配置
        throttle_classes = [MyThrottling]
    

    权限源码

# APIView的执行流程----》三大认证--->APIView的dispatch中写的---》APIView的self.initial(request, *args, **kwargs)三大认证----》APIView的self.check_permissions(request)
#主要是这三句话 先走认证在权限 频率 
self.perform_authentication(request) #认证
self.check_permissions(request) #权限
self.check_throttles(request) #频率
#########################权限认证
def check_permissions(self, request):
    #get_permissions配置在视图类中以permission_classes
    #self.get_permissions()==[权限类(加括号调用) 产生的对象,]
    for permission in self.get_permissions():
        #调用对象.has_permission(自己当成第一个参数传过去,request,当前类(APIView)的对象,self为当前类的对象)
        if not permission.has_permission(request, self):
            self.permission_denied(
                request,
                message=getattr(permission, 'message', None),
                code=getattr(permission, 'code', None)
            )
            
            
    def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        #列表推导式 permission_classes
        return [permission() for permission in self.permission_classes]

视图基类、视图子类、视图扩展类

两个视图基类 还需要写get post 等方法 
	APIView
    GenericAPIView    
    	定义了queryset 和 serializer_class  lookup_field 三个属性  第三个可以不写
        定义了 get_queryset 和 get_object 和 get_serializer 三个方法
五个视图拓展类 from rest_framework.mixins import 			
	UpdateModelMixin, #封装了update方法
	ListModelMixin,#封装了liste方法
    DestroyModelMixin,#封装了destroy方法
    RetrieveModelMixin,#封装了retrieve方法
    CreateModelMixin #封装了create方法
    但是如果实现多个接口需要多个继承 于是再次封装
九个视图子类 from rest_framework.generics import 
#内部把五个视图拓展类封装 +GenericAPIView
	ListAPIView,  #查询全部接口
	CreateAPIView,  #创建数据接口
    UpdateAPIView, #修改单个接口
    DestroyAPIView, #删除单条接口
    RetrieveAPIView, #查询单个接口
    ListCreateAPIView,  #查询全部和创建接口
    RetrieveDestroyAPIView, #查询单个和删除接口
    RetrieveUpdateAPIView, #查询单个和修改接口
    RetrieveUpdateDestroyAPIView,#查询单个和删除和修改接口
   #但是 还是需要写 那三个属性(第三个属性可写可不写)和 两个大方法 路由带参数的和不带参数的   于是出现了视图集 (可以自动或者手动生成路由写法改变了) 视图集都要继承ViewSetMixin+一个视图基类 
视图集from rest_framework.viewsets import 
	ModelViewSet,  #五个接口都有了 +GenericViewSet(ViewSetMixin,GenericAPIView)
    ReadOnlyModelViewSet, # 查询单个和所有接口+GenericViewSet(ViewSetMixin,GenericAPIView)
    ViewSet, # ViewSetMixin(执行他的as_view) 和 APIview (视图基类) 
    ViewSetMixin, #ViewSetMixin (可以自动或者手动生成路由)
    GenericViewSet, #ViewSetMixin +GenericAPIView
#ViewSetMixin 路由写法改变 重写了as_view,ViewSetMixin--》as_view--》路由写法改变了
	   -自动生成路由(SimpleRouter,DefaultRouter)
    	router.register('book','BookView')
        127.0.0.1:8080/book
#ViewSetMixin源码 
	重写了as_view 路由可以有一个方法了,不需要俩方法 也返回了view的内存地址  view里面action就是路由层传过来的字典 
    path('publish/', views.Publish.as_view({'get': 'list', 'post': 'create'})),
posted @ 2021-12-26 20:04  迪迦张  阅读(116)  评论(0编辑  收藏  举报