• 0102 三大视图配置


    昨日回顾

    1、三大认证:
    	认证组件:request.user登录用户
    	权限组件:user是否有权限
    	频率组件:3/min一分钟可以访问三次
    
    2、auth认证六表:User、Group、Permission、三个关系表
    
    3、自定义User表
    	1)自定义User继承AbstractUser
    	2)在settings中配置AUTH_USER_MODEL
    	3)admin注册自定义User表,配置UserAdmin
    	
    4、认证规则:session认证、jwt认证
    	jwt:json web token;只有客户端存储token;服务器只负责token签发与校验
    	jwt:header.payload.sign(头-基本信息.载荷-核心信息.签名-安全信息)
    	
    5、drf-jwt:
    	签发token、校验token、刷新token的三个视图类
    	认证组件(校验jwt token,得到登录用户user,存储到request.user中)
    

    router简单使用

    # 在view中
    
    from rest_framework.viewsets import GenericViewSet
    from rest_framework import mixins
    from . import models,serializers
    from .response import APIResponse
    class UserListAPIView(mixins.ListModelMixin, GenericViewSet):
        queryset = models.User.objects.filter(is_active=True).all()
        serializer_class = serializers.UserModelSerializer
    
        # 单改
        # 这些方法名,实在router组件中配置好的,可以从mixins中继承,也可以自定义方法体
        def update(self,request,*args,**kwargs):
            return APIResponse()
    
        # 群改
        def multiple_update(self,request,*args,**kwargs):
            return APIResponse(msg='群改')
        
        
    urls中配置
    
    from django.conf.urls import url, include
    from . import views
    
    from .router import router
    # eg: router.register('users', UserModelViewSet, basename='user')
    # 两个路由已经匹配了十个方法: get:retieve,list  post:create,create  put:update,multiple_update
    # 视图类用ViewSet或GenericViewSet的子类,在子类中实现对应的方法,就可以响应对应的请求
    router.register('users',views.UserListAPIView,basename='user')
    
    urlpatterns = [
        url(r'', include(router.urls))
    ]
    

    三大认证

    三大认证的流程图

    img

    自定义配置
    
        认证组件配置
            authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
    
        权限组件配置
            permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    
        频率组件配置
            throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
    
    ----------------------------------------------------
    
    全局配置
    
        认证
            'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication'
            ],
        权限
            'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.AllowAny',
            ],
        频率
            'DEFAULT_THROTTLE_CLASSES': [],
    

    1. 校验组件

    继承BaseAuthentication类,重写authenticate方法
    
    • 如果使用session认证,drf默认提供了SessionAuthentication
    • 如果使用drf-jwt认证框架,drf-jwt框架提供了``JSONWebTokenAuthentication` 方法
    • 如果是自定义签发与校验token,才需要将校验token的算法封装到自定义的认证类中

    1.1 源码

    img

    img

    img

    结论:

    • 提交了token,解析成功,返回(user, token) 组成的元组,代表合法用户
    • 元组0位user会被存储到request.user中
    • 元组1位token会被存储到request.auth中,通常也可以不用保存,所以可以用None填充

    1.2 自定义认证

    需求小

    配置路径 authentication_classes

    # 自定义认证组件,并设置 authentication_classes
    authentication_classes = [authentications.MyAuthentication]
    

    authentications文件中自定义认证类

    class MyAuthentication(BaseAuthentication):
        def authenticate(self, request):
            """
            步骤:
            1) 从请求头中拿到前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台约定)
                  -- 如果设置了反爬等措施,校验一下反爬(头 token)
            2)没有token,返回None,代表游客
            3)有token,进入校验
                  -- 不通过:抛AuthenticationFailed异常,代表非法用户
                  -- 通过:返回 (user, token),代表合法用户
            """
            pass
    

    1.3 drf认证类

    配置drf-jwt框架的认证类(需求大)

    • 配置还可以在全局(认证组件只能决定request.user,不是断定权限的地方,所以一般配置全局)
    views中设置
    
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    
    authentication_classes = [JSONWebTokenAuthentication]
    

    2. 权限组件

    2.1 drf权限类

    配置drf自带的权限类(有需求)

    from rest_framework.permissions import IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly
    
    permission_classes = [IsAuthenticated]
    permission_classes = [IsAdminUser]
    
    • drf默认提供了一些权限类

      • AllowAny:游客和登录用户有全权限
      • IsAuthenticated:只有登录用户有全权限
      • IsAdminUser:只有后台用户(admin用户)有全权限
      • IsAuthenticatedOrReadOnly:游客有读权限,登录用户有全权限
    • 如果有特殊需要,需要自定义权限类

      如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限
      

    2.2 自定义权限类

    继承BasePermission类,重写has_permission方法
    
    class MyPermission(BasePermission):
        def has_permission(self, request, view):
            """
            1) 根据需求,request和view的辅助,制定权限规则判断条件
            2)如果条件通过,返回True
            3)如果条件不通过,返回False
            """
            print(request.user, request.auth)
            return False
    

    在view中配置权限组件的设置permission_classes

    # 权限组件
    permission_classes = [permissions.MyPermission]
    

    2.3 总结

    认证与权限组件绑定使用
    
    • 1)每一个视图类都要进行认证校验,且认证规则一致,所以全局配置认证类即可
    • 2)每一个视图类都要进行权限校验,默认配置的是不限制(AllowAny),但实际开发中,视图类的访问权限不尽相同,所以要在具体的视图类,配置具体的权限规则

    权限与认证综合使用

    from rest_framework.viewsets import ViewSet
    class UserViewSet(ViewSet):
        # 权限:只有VIP用户可以查看个人详细详细
        permission_classes = [permissions.VIPUserPermission]
    
        def retrieve(self, request, *args, **kwargs):
            return APIResponse(results={
                'username': request.user.username,
                'email': request.user.email,
                'mobile': request.user.mobile,
                'data_joined': request.user.date_joined,
            })
    

    3. 频率组件

    3.1 源码

    img

    img

    img

    3.2 drf频率类

    配置drf自带的频率类(有需求)

    views中
    
    from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
    throttle_classes = [UserRateThrottle]
    

    在settings中配置

    # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置
    'DEFAULT_THROTTLE_RATES': {
        'user': '5/min',
        'anon': '3/min',
        'mobile': '1/min'
    },
    

    3.3 自定义频率类

    继承SimpleRateThrottle,定义scope字段属性,重写get_cache_key方法,并在settings中设置频率
    
    • drf默认提供了一些频率类

      AnonRateThrottle:只对游客进行频率限制
      UserRateThrottle:对所有用户进行频率限制
      
    • 如果有特殊需要,需要自定义频率类

      如:对ip进行限次、对电话进行限制、对视图某些信息进行限次
      

    配置自定义的频率类(需求大)

    views中:
    throttle_classes = [throttles.MobileRateThrottle]
    

    代码

    from rest_framework.throttling import SimpleRateThrottle
    
    class MobileRateThrottle(SimpleRateThrottle):
        """
        1)设置scope字符串类属性,同时在settings中进行drf配置DEFAULT_THROTTLE_RATES
            eg: DEFAULT_THROTTLE_RATES = {'mobile': '1/min'}
        2)重写get_catch_key方法:
            返回与限制条件有关的字符串,表示限制
            返回None,表示不限制
        """
        scope = 'mobile'
        def get_cache_key(self, request, view):
            if not request.user.is_authenticated or not request.user.mobile:
                return None  # 匿名用户 或 没有电话号的用户 都不限制
    
            # 只要有电话号的用户才进行限制
            return self.cache_format % {
                'scope': self.scope,
                'ident': request.user.mobile
            }
    
    

    4. 自定义签发token

    4.1 drf-jwt签发token

    源码解析

    img

    img

    img

    img

    img

    总结

    • username,password

      通过auth组件的authenticate方法得到 user对象

    • user对象

      通过drf-jwt框架的jwt_payload_handler函数包装 payload载荷

    • payload载荷

      通过drf-jwt框架的jwt_encode_handler函数签发 token字符串

    注: 可以借助jwt_payload_handlerjwt_encode_handler两个函数完成自定义jwt-token的签发

    img

    4.2 自定义签发token

    借助`jwt_payload_handler`和`jwt_encode_handler`两个函数完成自定义jwt-token的签发
    

    多方式登录签发token

    1.重点(局部禁用)

    • token只能由登录接口签发

    • 登录接口也是APIView的子类,使用一定会进行认证,权限,组件的校验

    • 不管系统默认,或是全局settings配置的是何认证与权限组件,登录接口不用参与任何认证与权限的校验

    • 所以,登录接口一定要进行认证与权限的局部禁用

      authentication_classes = []
      pagination_class = []
      

    2.序列化中自定义校验的字段

    post请求,序列化默认当成create动作进行校验,需要校验数据库,create动作username会报用户已存在异常
    
    抛用户已存在异常是多余的,所以自定义系统校验规则即可
    

    3.token的签发步骤

    • 通过username和password完成多方式登录校验,得到user对象

    • user对象包装payload载荷

    • payload载荷签发token

    • 将user与token存储到Serializer对象中,方便在视图类中使用

    • 自定义的获取user对象方法

      完成多方式登录的判断:邮箱,手机号,用户名校验
      

    代码实现

    在urls中设置自定义签发token的url

    from django.conf.urls import url, include
    from . import views
    from .router import router
    
    from rest_framework_jwt.views import ObtainJSONWebToken, obtain_jwt_token, refresh_jwt_token, verify_jwt_token
    
    urlpatterns = [
        # 自定义签发token的登录login接口
        url(r'^login/$', views.LoginAPIView.as_view()),
        
        url(r'', include(router.urls))
    ]
    

    views.py中设置类

    # 多方式登录
    from rest_framework.views import APIView
    class LoginAPIView(APIView):
    
        # 登录接口一定要进行 认证与权限 的局部禁用
        authentication_classes = []
        pagination_class = []
    
        def post(self, request, *args, **kwargs):
            # 将登录数据传入序列化得到Serializer对象
            serializer = serializers.LoginModelSerializer(data=request.data)
            # 对对象的数据进行校验(报错数据)
            serializer.is_valid(raise_exception=True)  # 内部在全局钩子中完成token的签发
            # 校验结束后的serializer对象存储着保存的user与token
            return APIResponse(results={
                'username': serializer.content.get('user').username,
                'token': serializer.content.get('token')
            })
    

    Serializers中定义序列化类

    from rest_framework_jwt.serializers import jwt_payload_handler,jwt_encode_handler
    class LoginModelSerializer(serializers.ModelSerializer):
        # post请求,序列化默认当成create动作进行校验,需要校验数据库,create动作username会报用户已存在异常
        # 抛用户已存在异常是多余的,所以自定义系统校验规则即可
        username = serializers.CharField(min_length=3,max_length=16)
        password = serializers.CharField(min_length=3,max_length=16)
        class Meta:
            model = models.User
            fields = ('username','password')
    
        # 用全局钩子,完成token的签发
        def validate(self, attrs):
            # 1.通过username和password完成多方式登录校验,得到user对象
            user = self._validate_user(attrs)
            # 2.user对象包装payload载荷
            payload = jwt_payload_handler(user)
            # 3.payload载荷签发token
            token = jwt_encode_handler(payload)
            # 4.将user与token存储到Serializer对象中,方便在视图类中使用
            self.content =  {
                'user':user,
                'token':token
            }
            return attrs
        # 自定义的获取user对象方法
        def _validate_user(self,attrs):
            username = attrs.get('username')
            password = attrs.get('password')
    
            if re.match(r'.*@.*',username):  # 邮箱校验
                user = models.User.objects.filter(email=username).first()
            elif re.match(r'1[3-9][0-9]{9}$',username):  # 电话校验
                user = models.User.objects.filter(mobile=username).first()
            else:   # 用户名
                user = models.User.objects.filter(username=username).first()
            # 校验user存在或者密码是否正确
            if not user or not user.check_password(password):
                raise serializers.ValidationError({'message':'用户信息异常'})
    
            return user
    

    总结

    1、认证组件
    * settings文件全局配置drf-jwt框架的认证类
    REST_FRAMEWORK = {
        # 认证组件
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
        ],
    }
    了解:如何自定义认证类、以及认证类规则
    
    2、权限组件
    * 视图类局部配置 drf自带 或 自定义 权限类
    class MyAPIView(APIView):
    	permission_classes = [permissions.VIPUserPermission]
    	
    * drf自带:IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly
    * 自定义:
    class VIPUserPermission(BasePermission):  # 只要vip分组用户有权限
        def has_permission(self, request, view):
            for group in request.user.groups.all():
                if group.name.lower() == 'vip':
                    return True  # 有权限
            return False  # 无权限
    
    3、频率组件
    * 视图类局部配置 drf自带 或 自定义 频率类
    class MyAPIView(APIView):
    	throttle_classes = [throttles.MobileRateThrottle]
    
    * drf自带:AnonRateThrottle, UserRateThrottle
    * 自定义:
    class MobileRateThrottle(SimpleRateThrottle):
        scope = 'mobile'
        def get_cache_key(self, request, view):
            if not request.user.is_authenticated or not request.user.mobile:
                return None  # 匿名用户 或 没有电话号的用户 都不限制
            return self.cache_format % {  # 只要有电话号的用户踩进行限制
                'scope': self.scope,
                'ident': request.user.mobile
            }
     配合settings中的频率配置
     REST_FRAMEWORK = {
        # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置
        'DEFAULT_THROTTLE_RATES': {
            'user': '5/min',
            'anon': '3/min',
            'mobile': '1/min'
        },
    }
    
    
    4、自定义签发token - 多方式登录
    1)将请求数据交给序列化类,执行序列化校验
    2)在序列化全局校验钩子中,完成user的认证与token的签发,保存在序列化对象的content中
    3)在视图类中从序列化对象的content中拿user与token相关信息返回
    注:多方式登录体现在 请求的账号类型可能是用户名、邮箱或手机等,采用不同字段校验数据库即可
    
  • 相关阅读:
    javascript中this使用规律
    call和apply的作用和不同
    SVN的标准目录结构:trunk、branches、tags
    SVN 多人修改,如何管理 关于版本的问题
    公司考勤系统项目设计
    CDI Features
    Java Design Pattern
    公司考勤系统设计文件
    spring( history Design Philosophy )
    JSON/xml
  • 原文地址:https://www.cnblogs.com/fwzzz/p/12143029.html
Copyright © 2020-2023  润新知