jwt在python项目中的应用

jwt

1.1 传统token认证
用户登录,服务器分发一个token,并将其保存在数据库中
当用户在访问时需要携带token,服务端获得token后会去数据库进行校验
1.2 jwt
用户登录,服务器分发一个token,但不保存
当用户在访问时需要携带token,服务端获得token后去校验

相较于传统token,jwt不需要在数据库中保存
1.2.1 jwt认证过程

img

1.3 python中的jwt
1.3.1 实现原理
  • 第一步用户登录时,使用jwt创建一个token返回给客户端

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    

    注意:jwt由三个部分组成,并且由"."链接

    • 第一段:HEADER:ALGORITHM & TOKEN TYPE

      ​ json转化为字符串,然后做 base64url 加密

      {
        "alg": "HS256", # 加密算法
        "typ": "JWT" # token类型
      }
      
    • 第二段:PAYLOAD:DATA

      {
        "sub": "1234567890",
        "name": "John Doe",
        "iat": 1516239022,
        "exp":datetime.datetime.utcnow() + datetime.timedelta(minutes=5) # 超时时间
      }
      

      注意:荷载主要存储的是用户传来的信息,但是可以被解密出来的,所以像密码之类的敏感信息不要往荷载里放

    • 第三段:VERIFY SIGNATURE

      第一步:将1,2部分的密文用"."拼接起来
      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
      第二步:对前两个部分的密文进行HS256加密+加盐
      第三步:对加密后的密文再进行 base64url 加密
      

      注意:最后一段的签名是当有前两段稍微有修改,第三段签名就会变化

  • 获取到前端传来的token,进行验证

    • 第一步,对token进行分割,以"."分割

      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
      
    • 第二步:获取第二段,在对其进行base64url解密获得payload,检测是否超时

      {
        "sub": "1234567890",
        "name": "John Doe",
        "iat": 1516239022,
        "exp":datetime.datetime.utcnow() + datetime.timedelta(minutes=5) # 超时时间
      }
      
    • 第三步:将1,2两部分拼接起来,对其进行sha256加密

      第一步:将1,2部分的密文拼接起来
      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
      第二步:对前两个部分的密文进行HS256加密+加盐
      密文 = base64解密(SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c)
      如果相等则验证通过,密文未被修改过
      
1.3.2应用
pip install pyjwt
pyjwt里面封装了上面的一些加密解密方法,直接调用即可
pyjwt.encode 生成token
pyjwt.decode token解密
1.3.2.1封装jwt应用
  • 创建文件夹,存放生成token的脚本:utils—>jwt_auth

    import datetime
    import jwt
    from django.conf import settings
    
    def create_token(payload,timeout=1):
        '''创建token'''
        salt = settings.SECRET_KEY
        # 构造header
        headers = {
            'typ': 'jwt',
            'alg': 'HS256'
        }
        # 构造payload,自己在view自定义要传的值,在方法里自动加上超时时间
        payload["exp"] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)  # 超时时间
    
    
        token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode('utf-8')
        return token
    
  • 创建文件夹,验证token : extensions----->auth

    import jwt
    
    from django.conf import settings
    from jwt import exceptions
    from rest_framework.response import Response
    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    
    
    class JwtQueryAuthentication(BaseAuthentication):
         '''
            jwt验证
            BaseAuthentication:用于拦截请求,在视图函数钱执行相应认证方法
            必须重写authenticate(self, request)方法,request参数必须传入
         '''
    
        def authenticate(self, request):
            token = request.query_params.get("token")
            salt = settings.SECRET_KEY
            try:
                payload = jwt.decode(token, salt, True)
            except exceptions.ExpiredSignatureError:
                raise AuthenticationFailed({"status": 1003, "error": 'token已失效'})
            except jwt.DecodeError:
                raise AuthenticationFailed({"status": 1004, "error": 'token认证失败'})
            except jwt.InvalidTokenError:
                raise AuthenticationFailed({"status": 1005, "error": '非法的token'})
            # if not payload:
            #     return Response({"status": 1003, "error": msg})
            return (payload, token)
    
            # 有三种操作
            # 1.验证失败,直接抛错不继续往下走了
            # 2.验证通过返回一个元组(1,2) ,在视图中调用request.user就是元组中的第一个值,调用request.auth是第二个值
            # 3.返回None,继续下个验证
    
  • 在视图里

    class loginJwtView(APIView):
        '''封装之后jwt分发token'''
        # 登录不需要验证
        authentication_classes = []
        def post(self, request, *args, **kwargs):
            # 这里简单写了,应该是先经过正常的登录认证在数据库里取到的值
            token = create_token({"username": request.data.get("username")}, timeout=2)
            return Response({"status": 200, "data": token})
    
    
    from jwtdemo.extensions.auth import JwtQueryAuthentication
    class orderJwtView(APIView):
        '''封装之后jwt验证token'''
        # 会先执行认证
        # 在settings设置不需要每个视图都加上authentication_classes
        # authentication_classes = [JwtQueryAuthentication, ]
    
        def get(self, request, *args, **kwargs):
            print(request.user, request.auth)
            return Response({"status": 200, "message": "验证成功"})
    
  • 当视图增多时,每次在视图前面加上authentication_classes = [JwtQueryAuthentication, ]便会显得很麻烦,这里在settings里设置

    REST_FRAMEWORK = {
        # 默认情况下,所有的页面都会加上jwt认证
        "DEFAULT_AUTHENTICATION_CLASSES":['jwtdemo.extensions.auth.JwtQueryAuthentication',]
    }
    

    注意:默认情况下,所有的页面都会加上jwt认证,所有登录页面要单独处理,加上authentication_classes = []

2.1 扩展
pip install djangorestframework-jwt
djangorestframework-jwt内部使用的就是pyjwt
3 参考

官网:https://jwt.io/

代码参考:https://www.cnblogs.com/wupeiqi/p/11854573.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值