zoukankan      html  css  js  c++  java
  • JWT和频率模块

    JWT

    jwt基本介绍

    全称:json web token

    随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。

    token的格式

    三段式 - 头.载荷.签名 - 头和载荷采用的是base64可逆加密,签名采用的是MD5不可逆加密

    token内容

    ​ 头(基础信息,也可以为空):加密方式、公司信息、项目组信息、...
    ​ 载荷(核心信息):用户信息、过期时间、...
    ​ 签名(安全保障):头加密结果+载荷加密结果+服务器秘钥 的md5加密结果

    安全保障

    安全保障主要靠的就是签名部分,比如Django的服务器密钥就是唯一的安全保障

    认证规则

    后台一定要保障 服务器秘钥 的安全性(它是jwt的唯一安全保障)
    后台签发token -> 前台存储 -> 发送需要认证的请求带着token -> 后台校验得到合法的用户

    使用jwt

    对认证模块进行封装,登录成功返回加密的token,还有解析token的功能

    首先要安装jwt。

    pip install djangorestframework-jwt
    

    jwt的三个主要功能

    三个视图接口

    jwt默认实现的功能过于简单,所以一般不直接使用他提供的视图接口

    url(r'^login1/$', obtain_jwt_token),
    
    #签发token,接收username和password
    obtain_jwt_token = ObtainJSONWebToken.as_view()
    
    #校验token,验证token,对的原样返回,错的报错
    refresh_jwt_token = RefreshJSONWebToken.as_view()
    
    #刷新token,使用要配置'JWT_ALLOW_REFRESH': False,允许刷新为True,token过期,刷新为有效时间
    verify_jwt_token = VerifyJSONWebToken.as_view()
    

    jwt配置

    JWT_AUTH = {
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    
        # 'JWT_ALLOW_REFRESH': True,
        # 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
    
        'JWT_AUTH_HEADER_PREFIX': 'JWT',
    }
    

    签发token流程

    user-->jwt_payload_handler-->payload-->jwt_encode_handler-->token

    #全局钩子,登录之后在序列化类里面做校验的时候就直接签发token。
       def validate(self, attrs):
            user = authenticate(**attrs)
            if not user:
                raise ValidationError({'user':'信息有误'})
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
    
            self.user = user
            self.token = token
    
            return attrs
    

    jwt全局认证

    # drf的配置
    REST_FRAMEWORK = {
        # 异常模块
        'EXCEPTION_HANDLER': 'utils.exception.exception_handler',
    
        # 认证模块
        'DEFAULT_AUTHENTICATION_CLASSES': [
            # jwt认证类
            'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        ],
        # 权限模块
        'DEFAULT_PERMISSION_CLASSES': [
            # 'rest_framework.permissions.IsAuthenticated',
            # 自定义权限类
        ],
        # 频率设置
        'DEFAULT_THROTTLE_RATES': {
            'three': '3/min',
        },
    }
    
    # 修改auth模块的用户表指向
    AUTH_USER_MODEL = 'api.User'
    
    
    # drf-jwt配置
    import datetime
    JWT_AUTH = {
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    
        # 'JWT_ALLOW_REFRESH': True,
        # 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
    
        'JWT_AUTH_HEADER_PREFIX': 'JWT',
    }
    
    

    多重登录

    class LoginAPIView(APIView):
        authentication_classes = []
        permission_classes = []
        def post(self, request, *args, **kwargs):
            serializer = serializers.LoginSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            return APIResponse(msg='login success', data={
                'username': serializer.user.username,
                'token': serializer.token
            })
    

    serializers:

    from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
    class LoginSerializer(ModelSerializer):
        username = CharField(write_only=True)
        password = CharField(write_only=True)
        class Meta:
            model = models.User
            fields = ('username', 'password')
    
        # 在全局钩子中签发token
        def validate(self, attrs):
            # user = authenticate(**attrs)
            # 账号密码登录 => 多方式登录
            user = self._many_method_login(**attrs)
    
            # 签发token,并将user和token存放到序列化对象中
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
    
            self.user = user
            self.token = token
    
            return attrs
    
        # 多方式登录
        def _many_method_login(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:
                raise ValidationError({'username': '账号有误'})
    
            if not user.check_password(password):
                raise ValidationError({'password': '密码有误'})
    
            return user
    

    综述一下 jwt

    就是三句代码,一句payload,一句token,一句settings的配置

    他帮你完成了用户认证,所以你只用写三大认证中的权限认证和频率认证。你只需要做的是,把用jwt把token生成了,然后放在user的名称空间里,校验token,由你在settings里配置的jwt部分来完成。

    频率模块

    自定义频率类完成视图类的频率限制
    1)定义类继承SimpleRateThrottle,重写get_cache_key方法,设置scope类属性
    2)scope就是一个认证字符串,在配置文件中配置scope字符串对应的频率设置
    3)get_cache_key的返回值是字符串,该字符串是缓存访问次数的缓存key

    在settings里的drf配置中写上这个

    'DEFAULT_THROTTLE_RATES': {
            'three': '3/min',
        },
    

    要自定义频率的视图类

    from rest_framework.permissions import IsAuthenticated
    from utils.throttles import ThreeTimeUserThrottle
    class UserCenterAPIView(APIView):
        # 认证全局配置吗,权限局部配置,认证已经交给jwt了
        # authentication_classes = []
        permission_classes = [IsAuthenticated]
        # 频率模块局部配置
        throttle_classes = [ThreeTimeUserThrottle]
    
        def get(self, request, *args, **kwargs):
            user = request.user
            serializer = serializers.UserModelSerializer(user)
            return APIResponse(data=serializer.data)
    
    

    throttles

    # 自定义频率类
    from rest_framework.throttling import SimpleRateThrottle
    # 1)定义类继承SimpleRateThrottle,重写get_cache_key方法,设置scope类属性
    # 2)scope就是一个认证字符串,在配置文件中配置scope字符串对应的频率设置
    # 3)get_cache_key的返回值是字符串,该字符串是缓存访问次数的缓存key
    class ThreeTimeUserThrottle(SimpleRateThrottle):
        #这里的scope要和settings里面的key对上。
        scope = 'three'
        # 当前用户缓存的key,这个方法的返回值是一个能够唯一标识用户的信息,如果name是唯一的,用name也行,总之它会认得这个字符串,知道下次进来的人是不是你。如果返回的字符串每次都是同样的,那么你所有用户登录就共用一个频率了。
        def get_cache_key(self, request, view):
            return 'throttle:user_%s' % (request.user.id)
    
  • 相关阅读:
    《学习OpenCV》第一版课后习题解答
    【练习8.11】等级匹配cvMatchContourTrees、凸缺陷计算cvConvexityDefects
    支持与不支持in-place操作的OpenCV函数汇总
    【练习8.10】直接使用cvFindContour的结果图片和cvDrawContour的方式提取Hu矩,观察在图片缩放或旋转时的稳定性
    【练习8.7】cvGoodFeaturesToTrack确定图像强角点、cvFindCornerSubPix亚像素级角点检测
    【练习8.6】使用不同参数值观察cvFindDominantPoints寻找关键点的效果
    【练习8.5】轮廓长度计算机cvApproxPoly逼近
    【练习8.2】使用指定标志创建序列cvCreateSeq、在序列中插入元素
    【练习8.1】查找轮廓、寻找关键点cvFindDominantPoints、访问序列中的元素
    C或C++中struct内存对齐计算精简方案
  • 原文地址:https://www.cnblogs.com/chanyuli/p/11966208.html
Copyright © 2011-2022 走看看