复习JWT原理和实战应用(django)

JWT原理和实战应用(django)

1、jwt

  • json web token, 一般用于用户认证(前后端分离,微信小程序,app开发)
    在这里插入图片描述

2、基于传统的token验证

  • 用户登录。服务端给返回token,并将token保存在服务端。
  • 之后用户在来访问时,需要携带token,服务端获取token后,再去数据库获取token进行校验。
from rest_framework.views import APIView
from rest_framework.response import Response
from APP import models

class ProLoginView(APIView):
    '''用户登录'''
    def post(self, request):
        user = request.data.get('username')
        password = request.data.get('password')
        user_object = models.User.objects.filter(username=user, password=password).first()
        if not user_object:
            return Response({'code': 400, 'error': '用户名或密码错误'})
        random_string = str(uuid.uuid4())

        user_object.token = random_string
        user_object.save()
        return Response({'code': 200, 'data': random_string})
    

class OrderView(APIView):
    """token验证"""
    def get(self, request, *args, **kwargs):
        token = request.query_params.get('token')
        if not token:
            return Response({'code': 400, 'error': "登录成功后才能访问"})
        user_object = models.User.objects.filter(token=token).first()
        if not user_object:
            return Response({'code': 400, 'errror': "token无效,请重新登录"})
        return Response('订单列表')
    

3、jwt——token

  • 用户登录,服务端给用户返回一个token(服务端不保存)。
  • 之后用户再来访问,需要携带token,服务端获取token后,在做token校验。
    • 优势:相较于传统token相比,他无需在服务端保存token。

4、jwt——token实现过程

  • 提交用户密码给服务端,如果登陆成功,使用jwt创建一个token,并给用户返回。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • 注意:jwt生成的token是三段字符串组成,并且连接起来。

    • 第一段字符串,HEADER,内部包含算法/token类型。json转化成字符串,然后做 base64url 加密以及遇到’+_'做特殊字符串替换)
    {
      "alg": "HS256",  # 算法
      "typ": "JWT"     # token类型
    }
    
    • 第二段字符串,payload,自定义值。json转化成字符串,然后做 base64url 加密以及遇到’+_'做特殊字符串替换)
    {
      "id": "1234567890",
      "name": "John Doe",
      "exp": 1516239022  # 超时时间
    }
    
    • 第三段字符串:
    第一步:12两部分密文拼接起来
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
    第二步:对前两部分密文进行HS256加密 + 加盐
    第三步:对HS256加密后的密文在做base64url加密
    
  • 之后用户再来访问,需要携带token,服务端对token进行校验。

    • 获取token
    • 第一步:对token进行切割
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    
    • 第二步:对第二段进行base64url解密,并获取payload信息,检测token是否已经超时。
    {
      "id": "1234567890",
      "name": "John Doe",
      "exp": 1516239022  # 超时时间
    }
    
    • 第三步:把第1,2端拼接,再次执行HS256加密
    第一步:12两部分密文拼接起来
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
    第二步:对前两部分密文进行HS256加密 + 加盐
    第三步:对HS256加密后的密文在做base64url加密(SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c)
    如果相等,表示token未被修改过(认证通过)
    

5、应用

基于Python的pyjwt模块创建jwt的token。

  • 安装

    pip3 install pyjwt
    
  • 实现

    import jwt
    import datetime
    from jwt import exceptions
    SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='
    def create_token():
        # 构造header
        headers = {
            'typ': 'jwt',
            'alg': 'HS256'
        }
        # 构造payload
        payload = {
            'user_id': 1, # 自定义用户ID
            'username': 'wupeiqi', # 自定义用户名
            'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5) # 超时时间
        }
        result = jwt.encode(payload=payload, key=SALT, algorithm="HS256", headers=headers).decode('utf-8')
        return result
    if __name__ == '__main__':
        token = create_token()
        print(token)
    

6、jwt校验token

一般在认证成功后,把jwt生成的token返回给用户,以后用户再次访问时候需要携带token,此时jwt需要对token进行超时合法性校验。

获取token之后,会按照以下步骤进行校验:

  • 将token分割成 header_segmentpayload_segmentcrypto_segment 三部分

    jwt_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
    signing_input, crypto_segment = jwt_token.rsplit(b'.', 1)
    header_segment, payload_segment = signing_input.split(b'.', 1)
    
  • 对第一部分header_segment进行base64url解密,得到header

  • 对第二部分payload_segment进行base64url解密,得到payload

  • 对第三部分crypto_segment进行base64url解密,得到signature

  • 对第三部分signature部分数据进行合法性校验

    • 拼接前两段密文,即:signing_input
    • 从第一段明文中获取加密算法,默认:HS256
    • 使用 算法+盐 对signing_input 进行加密,将得到的结果和signature密文进行比较。
import jwt
import datetime
from jwt import exceptions
def get_payload(token):
    """
    根据token获取payload
    :param token:
    :return:
    """
    try:
        # 从token中获取payload【不校验合法性】
        # unverified_payload = jwt.decode(token, None, False)
        # print(unverified_payload)
        # 从token中获取payload【校验合法性】
        verified_payload = jwt.decode(token, SALT, True)
        return verified_payload
    except exceptions.ExpiredSignatureError:
        print('token已失效')
    except jwt.DecodeError:
        print('token认证失败')
    except jwt.InvalidTokenError:
        print('非法的token')
if __name__ == '__main__':
    token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU"
    payload = get_payload(token)

7、获取封装的数据

示例:

class JwtQueryParamsAuthentication(BaseAuthentication):
    # 获取并判断token的合法性
    def authenticate(self, request):
        token = request.query_params.get('token')
        salt = settings.SECRET_KEY
        try:
            payload = jwt.decode(token, salt, algorithms=['HS256'])
        except exceptions.ExpiredSignatureError:
            raise AuthenticationFailed({'code': 400, 'error': "token已失效,请重新登录"})
        except jwt.DecodeError:
            raise AuthenticationFailed({'code': 400, 'error': "token认证失败"})
        except jwt.InvalidTokenError:
            raise AuthenticationFailed({'code': 400, 'error': "非法的token"})

        return (payload,token)

获取payload数据(示例):

class ProOrderView(APIView):
    def get(self, request):
        result = request.user
        print(result.get('name'))
        return Response(result)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值