• drf 三大认证详解


    drf 三大认证:

    认证:

    # 全局配置:
    	-在全局(认证组件只能决定request.user,不是断定权限的地方,所以一般配置全局)
        
    REST_FRAMEWORK = {
        # 认证组件
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
        ],
    }
    
    
    
    # 局部禁用(login 模块):
    
    authentication_classes = ''
    permission_classes = ''
    
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    # authentication_classes = [JSONWebTokenAuthentication]
    
    
    #自定义认证类:
        1) 如果使用session认证,drf默认提供了SessionAuthentication
        2) 如果使用drf-jwt认证框架,drf-jwt框架提供了JSONWebTokenAuthentication
        3) 如果是自定义签发与校验token,才需要将校验token的算法封装到自定义的认证类中
        
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    class MyAuthentication(BaseAuthentication):
        def authenticate(self, request):
            """
            1) 从请求头中拿到前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台约定)
                  -- 如果设置了反爬等措施,校验一下反爬(头 token)
            2)没有token,返回None,代表游客
            3)有token,进入校验
                  -- 不通过:抛AuthenticationFailed异常,代表非法用户
                  -- 通过:返回 (user, token),代表合法用户
            """
            pass
    
    
    
    #认证规则:
    	认证组件:校验用户 - 游客、合法用户、非法用户
        游客:代表校验通过,直接进入下一步校验(权限校验)
        合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
        非法用户:代表校验失败,抛出异常,返回403权限异常结果
        只要通过认证不管是游客还是登录用户,request.user都有值
    
    

    权限:

    #drf 自带权限组件:
    	IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly
    
    #自定义:
    自定义权限类:
    1) drf默认提供了一些权限类
        AllowAny:游客和登录用户有全权限
        IsAuthenticated:只有登录用户有全权限
        IsAdminUser:只有后台用户(admin用户)有全权限
        IsAuthenticatedOrReadOnly:游客有读权限,登录用户有全权限
    2)如果有特殊需要,需要自定义权限类
        如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限
        根据需求,request和view的辅助,制定权限规则判断条件
    
    默认权限:
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ],
    
    
    #permissions.py (vip 分组权限管理)
    from rest_framework.permissions import BasePermission
    class MyAPIView(APIView):
    	permission_classes = [permissions.VIPUserPermission]
        
    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  # 无权限
    
    
    

    认证与权限组件绑定使用:

        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,
            })
    

    频率:

    from rest_framework.throttling import SimpleRateThrottle
    """
    自定义频率类
    1) drf默认提供了一些频率类 
        AnonRateThrottle:只对游客进行频率限制
        UserRateThrottle:对所有用户进行频率限制
    2)如果有特殊需要,需要自定义频率类
        如:对ip进行限次、对电话进行限制、对视图某些信息进行限次
    """
    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
            }
    

    多方式登录:

    from rest_framework.views import APIView
    class LoginAPIView(APIView):
        """ 重点
        1)token只能由 登录接口 签发
        2)登录接口也是APIView的子类,使用一定会进行 认证、权限 组件的校验
        结论:不管系统默认、或是全局settings配置的是何认证与权限组件,登录接口不用参与任何认证与权限的校验
        所以,登录接口一定要进行 认证与权限 的局部禁用
        """
        authentication_classes = []
        pagination_class = []
    
        def post(self, request, *args, **kwargs):
            serializer = serializers.LoginModelSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)  # 内部在全局钩子中完成token的签发
            return APIResponse(results={
                'username': serializer.content.get('user').username,
                'token': serializer.content.get('token')
            })
    
    #serializer.py
    
    from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
    import re
    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
    
        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()  # type: models.User
            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()
    
            if not user or not user.check_password(password):
                raise serializers.ValidationError({'message': '用户信息异常'})
    
            return user
    
    自定义签发token :
    
        1)将请求数据交给序列化类,执行序列化校验
        2)在序列化全局校验钩子中,完成user的认证与token的签发,保存在序列化对象的content中
        3)在视图类中从序列化对象的content中拿user与token相关信息返回
        注:多方式登录体现在 请求的账号类型可能是用户名、邮箱或手机等,采用不同字段校验数据库即可
    
  • 相关阅读:
    Linux五种IO模型性能分析
    并发容器之CopyOnWriteArrayList(转载)
    Web.XML配置详解
    Servlet,过滤器,监听器,拦截器的区别
    JAVA反射机制详解
    Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue
    Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue
    Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer
    Jdk1.6 JUC源码解析(7)-locks-ReentrantLock
    hibernate 其中七种关联关系
  • 原文地址:https://www.cnblogs.com/shaozheng/p/12141576.html
Copyright © 2020-2023  润新知