首页 > 其他 > 详细

JWT

时间:2020-07-11 00:22:32      阅读:91      评论:0      收藏:0      [点我收藏+]

 

什么是JWT?

  json web token,一般用于用户认证(前后端分离/微信小程序/app开发)

 

 

传统的token验证工作流程:

用户登录,后台效验用户名和密码正确会生成一个Token(随机的字符串),会在数据库保存一份,然后将生成的token返回给前端,下次用户访问其他页面会带着token,
根据这个token去数据库里对比判断用户是否登录。

 

          技术分享图片

 

实现代码:

# 创建一个Django项目
    我们用restframework来写,注意在settings里的app里要把rest_framework加上
  技术分享图片
# 创建一个model表,要有token字段

         技术分享图片

# 写urls

         技术分享图片

# 在views里写
from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
import uuid
# Create your views here.
class LoginView(APIView):
    def post(self,request,*args,**kwargs):
        name = request.data.get(name)
        pwd = request.data.get(password)
        userobj = models.UserInfo.objects.filter(name=name,password=pwd).first()
        if not userobj:
            return Response({code: 300, msg: 用户名密码错误})
        token = str(uuid.uuid4())
        userobj.token = token
        userobj.save()
        return Response({code:100,msg:登录成功})

class OrderView(APIView):
    def get(self,request,*args,**kwargs):
        token = request.query_params.get(token)
        print(token,request.query_params)
        if not token:
            return Response({code:301,msg:请登录后访问})
        user_obj = models.UserInfo.objects.filter(token=token).first()
        if not user_obj:
            return Response({code:302,msg:token失效,请重新登录})
        return Response(订单页面)

 

# 用postman测试

 技术分享图片

-----------------------------------------------------------------------------------------------------------------------------

技术分享图片

登录成功后会在数据库里产生token

 

不带token访问会要求登录后访问

技术分享图片

乱带一个会校验token

技术分享图片

带数据库里的token才可以查看信息

技术分享图片

 

 

这是传统的token验证的做法

技术分享图片

 

 

 

 

 

技术分享图片

下面来介绍一下JWT的原理及实现方法

  

    https://jwt.io/#debugger-io

技术分享图片

 

 

 

用户提交用户名和密码给服务端如果登录成功,使用jwt创建一个token,并给用户返回

eyJhbGciOiJIUzIINiIsInR5cCI6IkpxvCJ9. eyJzdwIioiIxMjMONTY3ODkwIiwibmFtZSI6IkpvaG4gRG91Iiwi awFOIjoxNTE2MjM5MDIyfQ. Sf1KxwRJSMeKKF 2QT4fwpMeJf36POk6yJV_ adQssw5c

注意: jwt 生成的 token 是由三段字符串组成并且用 "." 连接起来。

 

 

Token的加密过程

 

第一段字符串,HEADER,内部包含算法/token类型

json转化成字符串,然后做base64url加密(base64加密;里面的“+”,“/”等换成“_”)


{
"a1g": "HS256", "typ": "JWT" }

 

第二段字符串,payload,自定义值

json转化成字符串,然后做base64url加密(base64加密;里面的“+”,“/”等换成“_”)

{
    "id"; "123123",
    "name": "chenggen""exp": 1516239022 #超时时间
}

 

第三段字符串:

第一步:第1,2部分密文拼接起来
eyJhbGcioiJIUzIINiIsInR5cCI6IkpXVC19.eyJzdwIioiIxMjMONTY30DkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaNFOIjoxNTE2MjM5MDIyfQ

第二步:对前2部分密文进行HS256加密+加盐

第三步:对HS256加密后的密文再做base64ur1加密

 

 

 后端的效验过程

以后用户再来访问时候需要携带token,后端霖要对token进行校验。

 

获取token

第一步:对token进行切割

eyJhbGcioiJIUzIINiIsInRScCI6IkpXVCJ9. eyJzdwIiOiIxMjMONTY30DkwIiwibmFtZSI6IkpvaG4gRG91Iiwi alwFOIjoxNTE2MjM5MDIyfQ. Sf]KxwRJSMeKKF 2QT4fwpMeJf36POk6yJV_ adQssw5c

 

第二步:对第二段进行base64url解密,并获取payload信息检测token是否已经超时?

{
  "
id": "123123",   "name": ”chenggen"   "exp": 1516239022 #超时时间
}

 

第三步:把第1,2端拼接再次执行sha256加密”

第一步:第1,2部分密文拼接起来

eyJhbGcioiJIUzINiIsInRScCI6IkpXVC39.eyJzdwTi0iTxMjMONTY30DkwIiwibmFtZSI6IkpvaG4gRG9lIiwiainFOIjoxNTE2MjM5MDIyfQ

第二步:对前2部分密文进行HS256加密+加盐

密文= base64解密(sf1KxwRJSMeKKF2QT4fwpMeJf36POk6yJV adQssw5c)如果相等,表示token未被修改过. (认证通过)

 

 Jwt的应用

 

安装:pip install pyjwt
class JwtLoginView(APIView):
    def post(self,request,*args,**kwargs):
        name = request.data.get(name)
        pwd = request.data.get(password)
        userobj = models.UserInfo.objects.filter(name=name,password=pwd).first()
        if not userobj:
            return Response({code: 300, msg: 用户名密码错误})
        import jwt
        import datetime

        salt = deghrtyjtdhtegjdyujhtjhrgtrjttf
        # 构造header , 这里不写默认的也是
        headers = {
            typ: jwt,
            alg: HS256
        }
        # 构造payload
        payload = {
            user_id: userobj.id,  # 自定义用户ID
            username: userobj.name,  # 自定义用户名
            exp: datetime.datetime.utcnow() + datetime.timedelta(minutes=5)  # 超时时间,取现在时间,五分钟后token失效
        }
        token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode(utf-8)
        return Response({code:100,msg:登录成功,token:token})



postman 测试
技术分享图片

 

 

 

 

JWTorder页面

class JwtOrderView(APIView):
    def get(self,request,*args,**kwargs):
        import jwt
        from jwt import exceptions
        salt = deghrtyjtdhtegjdyujhtjhrgtrjttf
        token = request.query_params.get(token)
        payload = None
        msg = None

        try:
            payload = jwt.decode(token,salt,True)
        except exceptions.ExpiredSignatureError:
            msg = token已失效
        except jwt.DecodeError:
            msg = token认证失败
        except jwt.InvalidTokenError:
            msg = 非法的token
        if not payload:
            return Response({code:303,error:msg})
        print(payload[user_id],payload[username])
        return Response(订单页面)

技术分享图片

 

 

 

 

 

在项目中这么写会很乱,所以我们可以子自定义写文件导入

 

urls.py

url(r^pro/login/$, views.ProLoginView.as_view()),
url(r^pro/order/$, views.ProOrderView.as_view()),

自定义文件

技术分享图片

 

 auth.py

from django.conf import settings
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import jwt
from jwt import exceptions

class JwtQueryParamsAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 获取token并判断token的合法性
        token = request.query_params.get(token)
        salt = settings.SECRET_KEY
        try:
            payload = jwt.decode(token,salt,True)
        except exceptions.ExpiredSignatureError:
            raise AuthenticationFailed({code:1003,error:token已失效})
        except jwt.DecodeError:
            raise AuthenticationFailed({code:1003,error:token认证失败})
        except jwt.InvalidTokenError:
            raise AuthenticationFailed({code:1003,error:非法的token})
        # 三种操作
         #1.抛出异常,后续不在执行
         #2.return一个元组(1,2),认证通过,在视图中如果调用request.user就是元组的第一个值,requset.auth就是第二个值
         #3.None
        return (payload,token)

jwt_auth.py

import jwt
import datetime
from django.conf import settings

def create_token(payload,timeout=5):
    salt = settings.SECRET_KEY
    # 构造header
    header = {
        typ:jwt,
        alg:HS256
    }
    # 构造payload
    payload[exp] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
    token = jwt.encode(payload=payload,key=salt,algorithm="HS256",headers=header).decode(utf-8)
    return token

views.py

from app01.extensions.auth import JwtQueryParamsAuthentication
from app01.utils.jwt_auth import create_token
class ProLoginView(APIView):
    def post(self,request,*args,**kwargs):
        name = request.data.get(name)
        pwd = request.data.get(password)
        user_obj = models.UserInfo.objects.filter(name=name,password=pwd).first()
        if not user_obj:
            return Response({code:301,error:用户名或密码错误})
        token = create_token({id:user_obj.id,name:user_obj.name})
        return Response({code:302,data:token})

class ProOrderView(APIView):
    authentication_classes = [JwtQueryParamsAuthentication,]
    def get(self,request,*args,**kwargs):
        print(request.user)
        return Response(订单列表)

 

 

最后在settings里设置一个全局的认证

REST_FRAMEWORK = {
    DEFAULT_AUTHENTICATION_CLASSES:[app01.extensions.auth.JwtQueryParamsAuthentication]
}

这样写的话全局都会有token认证,但是登陆页面我们不能验证,否则会死循环了,只需要加

authention_classes = []

 

JWT

原文:https://www.cnblogs.com/tuzaizi/p/13282028.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!