python-JWT(Json Web Token)-pyjwt
2021-04-09 04:26
标签:可扩展性 失败 方法 work code salt 校验 加密原理 token 1. 用户第一次登录时, 生成一个token并返回给前台, 同时将其与用户主键一同存在后台服务器上(数据库或缓存中) 1. token存在后台, 增加了存储和读取的开销 1. 用户第一次登录时, 生成一个token, 但后台不存储该token 2. 下一次访问需要登录的页面时, 将token一起传入 3. 后台拿着token进行解析和校验, 若解析成功则认证通过, 否则认证不通过 生成的token分为三个部分: HEADER.PAYLOAD.SIGNATURE, 这三个部分都是可逆算法base64加密后的字符串, 最后用点号(.)拼接.如: 代表了加密算法和token类型, 若不显示指定, 默认为: 代表了想要传输的业务信息和token的过期时间(可选), 例如: JWT的关键, 其规则是将前面两段加密后的密文再加上自定义的盐值一起拼接后, 再通过不可逆算法HS256(具体使用的是HEADER中的算法)进行加密, 最后再对该密文进行可逆算法base64加密 盐值(salt): 指的是加密时加入的自定义的字符串, 最好是随机或者杂乱的字符串, 这样更能够确定加密后字符串的唯一性, django中可以使用settings中的SECRET_KEY 加密后结果为: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c 拿到请求中传过来的token后: JWT的根本思想就是将业务数据通过不可逆算法加密存储在token中, 那么为什么要搞成三段式这么复杂呢? 这是python使用JWT的基础包, 在jwt官网中python语言点赞最多的就是pyjwt, 安装方式为: pip install pyjwt , 这个包已经把加密和解密的逻辑写好了, 我们只需要传入加密算法/业务数据/盐值即可 定义两个接口, 登录(login)和查看订单(order), 只有登录过的用户才能成功访问查看订单接口, 我们可以在登录接口中若成功登录则返回jwt的加密token, 在订单接口中自定义一个认证类, 在认证类中校验token 1. 登录成功后, 调用获取token的方法 create_token() , 传入参数为用户信息和token过期时间(单位: 分钟), 默认1分钟 2. 在订单视图类中设置认证类 JWTAuthentication 3. create_token和JWTAuthentication都定义在utils包的JWTAuth.py中 注意: 设置过期时间时, 一定是在payload段中设置, 且键名固定为‘exp‘, 值为 datetime.datetime.utcnow() + datetime.timedelta(xxxx) python-JWT(Json Web Token)-pyjwt 标签:可扩展性 失败 方法 work code salt 校验 加密原理 token 原文地址:https://www.cnblogs.com/gcxblogs/p/13376058.htmlJWT的引入
传统登录认证流程:
2. 下一次访问需要登录的页面时, 将token一起传入
3. 后台拿着token去数据库或缓存中查找是否存在该token, 存在则认证通过, 否则认证不通过传统认证的缺点:
2. 当存在多个后台服务器时, 需同步共享token, 比较麻烦JWT认证流程(解决了传统认证的问题):
JWT加密原理:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
1. HEADER
{
"alg": "HS256",
"typ": "JWT"
}
加密后结果为: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ92. PAYLOAD
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 451154141
}
加密后结果为: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ3. SIGNATURE
JWT解密原理:
1. 按.号拆分token, 拿到三段值
2. 对这三段密文进行base64解密, 从明文中拿到加密算法和业务数据以及过期时间
3. 再次拼接前两段的密文和自定义的盐值(该盐值必须和创建token时的盐值一样), 使用HEADER中的算法进行加密
4. 将加密的结果和拿到的token中的第三段解密的明文进行比较, 若完全一致则说明认证成功, 若不一致则说明token被篡改过, 认证失败对JWT三段式的思考:
直接把业务数据加上盐值, 然后用默认不可逆算法生成一段密文字符串进行传输不就可以了吗?
这样加密时是比较简单, 但是解密时却由于不可逆算法而拿不到其中的业务数据, 所以确实需要再加一段式来单独存储业务数据
JWT又加了一段用来存储加密算法, 能够让使用者自己确定具体使用什么算法进行加密, 增加了可扩展性python中使用JWT
pyjwt
在rest_framework中使用pyjwt
1. 编辑urls.py
from django.urls import path
from users import views
urlpatterns = [
path(‘login/‘, views.LoginView.as_view()),
path(‘order/‘, views.OrderView.as_view()),
]
2. 编辑登录和订单视图类
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.JWTAuth import create_token, JWTAuthentication
class LoginView(APIView):
def post(self, request, *args, **kwargs):
# 获取用户名密码
name = request.data.get(‘name‘)
pwd = request.data.get(‘pwd‘)
# 获取User对象
try:
user = models.User.objects.filter(name=name, pwd=pwd).first()
except Exception:
return Response({‘status‘: 1, ‘errmsg‘: ‘用户名或密码不正确!‘})
# 获取token
token = create_token({‘id‘: user.id, ‘name‘: user.name}, 1)
# 返回成功响应
return Response({‘status‘: 0, ‘token‘: token})
class OrderView(APIView):
authentication_classes = [JWTAuthentication, ]
def get(self, request):
return Response({‘status‘: 0, ‘msg‘: ‘ok‘})3. 编辑JWTAuth.py
import jwt
from jwt import exceptions as JWTException
from django.conf import settings
import datetime
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
def create_token(payload, timeout=1):
# 给传过来的业务数据增加一个过期时间限制
payload[‘exp‘] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
# 定义盐值
salt = settings.SECRET_KEY
# 默认不可逆加密算法为HS256
token = jwt.encode(payload=payload, key=salt)
return token
class JWTAuthentication(BaseAuthentication):
def authenticate(self, request):
# 从url参数中获取token
token = request.query_params.get(‘token‘)
# 盐值
salt = settings.SECRET_KEY
# 解码token
try:
payload = jwt.decode(jwt=token, key=salt, verify=True)
except JWTException.ExpiredSignature:
raise AuthenticationFailed(‘token已失效‘)
except jwt.DecodeError:
raise AuthenticationFailed(‘token认证失败‘)
except jwt.InvalidTokenError:
raise AuthenticationFailed(‘非法的token‘)
return payload.get(‘name‘), token
上一篇:Java数据类型
文章标题:python-JWT(Json Web Token)-pyjwt
文章链接:http://soscw.com/index.php/essay/73173.html