当前位置: 首页 > news >正文

flask 之JWT认证实现

目录

1、JWT

1.1、JWT概述

1.2、token的生成

1.3、token校验

1.4、flask项目中实现JWT认证

1、JWT

1.1、JWT概述

JWT(JSON Web Token)是一种用于身份验证和授权的开放标准。它由三部分组成,分别是头部、负载和签名。

头部(Header)是一个 JSON 对象,描述了使用的算法和类型。它通常包含两个字段:算法(alg)和类型(typ)。

负载(Payload)也是一个 JSON 对象,用于存储用户的相关信息。它可以包含一些预定义的字段,如过期时间(exp)、发布时间(iat)等,也可以包含一些自定义字段。

签名(Signature)使用指定的算法对头部和负载进行加密,生成一段字符串。这个字符串可以用于验证数据的完整性。

1、传统的token认证流程

  1. 用户登录:用户输入用户名和密码,向服务器发送登录请求。
  2. 生成token:服务器验证用户名和密码的正确性,如果验证通过,则生成一个随机字符串作为token,并将这个token与用户ID等关键信息关联起来(例如,将token和用户ID作为键值对存储在Redis等缓存中)。
  3. 返回token:服务器将生成的token返回给客户端,客户端将token保存在cookie或localStorage中。
  4. 携带token:当客户端需要访问需要认证的接口时,会在请求头中携带这个token。
  5. 验证token:服务器在接收到请求后,会从请求头中提取token,并根据token在缓存中查找对应的用户信息。如果找到了对应的用户信息,则说明用户已经登录且token有效;否则,说明用户未登录或token已过期。

2、传统token认证流程和JWT的对比

  1. 存储方式:传统token方式需要将token保存在服务器端(如Redis),而JWT则将token的所有信息都包含在token本身中,无需在服务器端保存。
  2. 安全性:JWT通过签名机制来确保数据的完整性和防止篡改,而传统token方式则更依赖于服务器端的验证。
  3. 应用场景:JWT更适用于分布式系统或跨域请求的场景,而传统token方式则更适用于传统的Web应用。

1.2、token的生成

jwt的生成token格式如下,即:由 . 连接的三段字符串组成。

eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJ1c2VybmFtZSI6ImxqIiwiZXhwIjoxNzE2NzkyODI4fQ.WrT1XY8CC1vFo8tPpt0ZrDjje5ooD8hTOvIW42Z2WEo

1、生成规则如下:

  • token组成:将三段字符串通过 . 拼接起来就生成了jwt的token。
  • 第一段HEADER部分,固定包含算法和token类型,对此json进行base64url加密,这就是token的第一段。
headers = {'typ': 'jwt','alg': 'HS256'
}
  • 第二段PAYLOAD部分,包含一些数据,对此PAYLOAD进行base64url加密,这就是token的第二段
payload = {'user_id':1,'username':'张三', 'role':'admin','exp': "XXX"...........
}
  • 第三段SIGNATURE部分,把前两段的base密文通过.拼接起来,然后对其进行HS256加密,再然后对hs256密文进行base64url加密,最终得到token的第三段。
base64url(HMACSHA256(base64UrlEncode(headers) + "." + base64UrlEncode(payload),secret # 秘钥加盐)
)

注意:base64url加密是先做base64加密,然后再把 - 替换 + _ 替换 / 。

2、代码实现:

  • 使用的库是:pyjwt模块。
  • 安装库:

pip install pyjwt

代码实现:

import jwt
import datetime# 秘钥加盐
SALT = 'adasfasfgthfafklsaj?lkasld;)(hjasgbsvbfjh='def create_token():# headerheaders = {'typ': 'jwt','alg': 'HS256'}# payloadpayload = {'user_id': 1,  # 自定义用户ID'username': '张三',  # 自定义用户名'role': "admin", # 自定义角色'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=2)  # 过期时间(2个小时)}result = jwt.encode(headers=headers, payload=payload, key=SALT, algorithm=["HS256"])return resultif __name__ == '__main__':token = create_token()print(token)

1.3、token校验

获取token之后,会按照以下步骤(主要是进行超时和合法性校验)进行校验:

  • 将token分割成 header_segment、payload_segment、crypto_segment 三部分
  • 对第一部分header_segment进行base64url解密,得到header
  • 对第二部分payload_segment进行base64url解密,得到payload
  • 对第三部分crypto_segment进行base64url解密,得到signature后进行合法性校验。
    • 拼接前两段密文,即:signing_input
    • 从第一段明文中获取加密算法,默认:HS256
    • 使用 算法+盐 对signing_input 进行加密,将得到的结果和signature密文进行比较。

代码实现:

import jwt# 秘钥加盐
SALT = 'adasfasfgthfafklsaj?lkasld;)(hjasgbsvbfjh='def get_payload(token):try:# 校验token合法性和是否超时verified_payload = jwt.decode(jwt=token, key=SALT, verify=True, algorithms=["HS256"])return verified_payloadexcept jwt.ExpiredSignatureError:print("token已过期")except jwt.DecodeError:print('token认证失败')except jwt.InvalidTokenError:print('非法的token')if __name__ == '__main__':token = "eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Ilx1NWYyMFx1NGUwOSIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNzQwMDIwMn0.iXqTAykKdA8ln0WMCsdhcc3Je0l4qOvYoxctkjEmhHs"payload = get_payload(token)print(payload)

1.4、flask项目中实现JWT认证

项目的目录结构如下:

1、app.py文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-import base64
from flask import Flask, request, jsonify, g
from utils.jwt_auth import create_token, check_tokenapp = Flask(__name__)# 通过url传递token
# 每一个请求前都进行token的验证
# @app.before_request
# def jwt_query_params_auth():
#     if request.path == '/login/':
#         return
#     token = request.args.get('token')
#     result = check_token(token)
#     if not result['status']:
#         return jsonify(result)
#     g.user_info = result['info']# 通过Authorization请求头传递token@app.before_request
def jwt_authorization_auth():if request.path == '/login/':return# 在实际项目中Authorization的组成一般是: Bearer toeknauthorization = request.headers.get('Authorization', '')token = ""# 对head进行解密if authorization:# 获取token信息token = authorization.split(" ")[1]# 获取token中的header加密部分encoded_header = token.split(".")[0]# 注意:我们需要替换字符并确保字符串长度是 4 的倍数padded = encoded_header + '=' * (-len(encoded_header) % 4)# 对header进行base64url解密header = base64.urlsafe_b64decode(padded.replace('-', '+').replace('_', '/')).decode('utf-8')print(header)result = check_token(token)if not result['status']:return jsonify(result)g.user_info = result['info']@app.route('/login/', methods=['POST'])
def login():user = request.form.get('username')pwd = request.form.get('password')print(user)# 检测用户和密码是否正确,此处可以在数据进行校验。if user == '张三' and pwd == '123456':# 用户名和密码正确,给用户生成token并返回token = create_token({'user_id':1, 'username':'张三', 'role':'admin'})return jsonify({'status': True, 'token': token})return jsonify({'status': False, 'error': '用户名或密码错误!'})@app.route('/info/')
def order():print(g.user_info)return jsonify(g.user_info)if __name__ == '__main__':app.run(debug=True)

2、jwt_auth.py文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import jwt
import datetime# 秘钥加盐
SALT = 'adasfasfgthfafklsaj?lkasld;)(hjasgbsvbfjh='def create_token(payload, timeout=60):""":function: 创建token:param payload:  例如:{'user_id':1,'username':'张三', 'role':'admin'}用户信息:param timeout: token的过期时间,默认60分钟:return:"""headers = {'typ': 'jwt','alg': 'HS256'}payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)result = jwt.encode(headers=headers, payload=payload, key=SALT, algorithm="HS256")return resultdef check_token(token):""":function: 检验token的合法性和是否过期:param token: 用户token信息:return: 返回检验结果"""result = {'status': False, 'info': None, 'msg': None}try:print(token)verified_payload = jwt.decode(jwt=token, key=SALT, verify=True, algorithms=["HS256"])result['status'] = Trueresult['info'] = verified_payloadexcept jwt.ExpiredSignatureError:result['msg'] = 'token已失效'except jwt.DecodeError:result['msg'] = 'token认证失败'except jwt.InvalidTokenError:result['msg'] = '非法的token'return result

相关文章:

  • 系统安全及其应用
  • 一种用于异质结高电子迁移率晶体管(HEMTs)的紧凑型漏电流模型,其中包括双子带的二维电子气(2DEG)密度解
  • Zookeeper复习
  • 力扣2106.摘水果
  • Python正则表达式:深度解析URL匹配与操作
  • 【康耐视国产案例】智能AI相机联合OSARO为Zenni眼镜实现订单履约自动化
  • 深度神经网络——什么是扩散模型?
  • 用c#开发在linux环境下运行的程序
  • 微信小程序canvas画图使用百分比适配不同机型屏幕达到任何屏幕比例皆可!完美适配任何机型!指定canvas尺寸适配亦可!保证全网唯一完美
  • WPF中Ignorable
  • AVL许可安全性问题
  • 【Python】教你彻底了解Python中的正则表达式
  • JAVA小案例-分别计算100以内奇数和偶数的和
  • SAP 限制物料类型在BOM组件中简介
  • 2024FIC初赛
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • JAVA并发编程--1.基础概念
  • js面向对象
  • js作用域和this的理解
  • Laravel Mix运行时关于es2015报错解决方案
  • Phpstorm怎样批量删除空行?
  • Python_OOP
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 基于web的全景—— Pannellum小试
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 每天10道Java面试题,跟我走,offer有!
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 驱动程序原理
  • 如何使用 JavaScript 解析 URL
  • 什么软件可以剪辑音乐?
  • 树莓派 - 使用须知
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 主流的CSS水平和垂直居中技术大全
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​LeetCode解法汇总518. 零钱兑换 II
  • # 职场生活之道:善于团结
  • #php的pecl工具#
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • (4) PIVOT 和 UPIVOT 的使用
  • (function(){})()的分步解析
  • (已解决)Bootstrap精美弹出框模态框modal,实现js向modal传递数据
  • (转)树状数组
  • *(长期更新)软考网络工程师学习笔记——Section 22 无线局域网
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .Net Remoting常用部署结构
  • .net 程序发生了一个不可捕获的异常
  • .net 后台导出excel ,word
  • .NET 设计模式初探
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET构架之我见
  • .NET运行机制