jwt认证课件讲解
JWT
基本概念
在用户登录后,我们需要在不同请求之间记录用户的登录状态,常用方式一般有三种:Cookie,Session和Token。
这里我们使用第三种Token令牌方式来实现认证鉴权,采用Json Web Token认证机制(简称:jwt)。
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
jwt官网:https://jwt.io/
jwt规范:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token
JWT的构成
JWT就一段由三段信息构成的字符串,将这三段信息文本用.
拼接一起就构成的。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
jwtToken = f"{header}.{payload}.{signature}"
header
jwt的头部承载两部分信息:
- typ: type的缩写,声明token的类型,值一般可以是
JWT
或Bear
。 - alg: algorithm的缩写,声明token的第三方部分(签证)的加密算法,通常直接使用
HMAC SHA256
完整的头部就像下面这样的JSON:
{"typ": "Bear","alg": "HS256"
}
然后将头部进行base64.b64urlencode()编码,构成了第一部分头部。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
python代码实现过程:
import base64,json
data = {'typ': 'JWT','alg': 'HS256'
}header = base64.b64encode(json.dumps(data).encode()).decode()# 各个语言中都有base64加密解密的功能,所以我们jwt为了安全,需要配合第三段加密
payload
载荷(payload)就是jwt存放有效信息的部分。这个名字像是特指飞机上承载的货仓,这些有效信息包含三种不同类型的数据:
- 标准声明
- 公共声明
- 私有声明
标准声明 (官方提出建议但不强制使用) :
-
iss: jwt签发者
-
sub: jwt所面向的用户
-
aud: 接收jwt的一方
-
exp: jwt的过期时间,这个过期时间必须要大于签发时间
-
nbf: 定义在什么时间之后,该jwt可以正常使用。
-
iat: jwt的签发时间
-
jti: jwt的唯一身份标识,主要用来作为一次性token,往往采用UUID字符串或随机字符串来充当。
以上是JWT规范中提供的7个官方字段,开发者根据自己的业务进行选用。
公共声明:公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端直接可以查看。
私有声明:私有声明是服务端和客户端所共同定义的声明,一般使用类似ace算法进行非对称加密和解密的,意味着该部分信息可以归类为明文信息。
定义一个payload,json格式的数据:
{"sub": "1234567890", // 时间戳"exp": "3422335555", // 时间戳"name": "John Doe","admin": true,
}
然后将其进行base64.b64encode() 编码,得到JWT的第二部分。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
python代码实现过程:
import base64,json
data = {"sub": "1234567890","exp": "3422335555","name": "John Doe","admin": True,"info": "232323ssdgerere3335dssss"
}payload = base64.b64encode(json.dumps(data).encode()).decode()# 各个语言中都有base64编码和解码,所以我们jwt为了安全,需要配合第三段签证来进行加密保证jwt不会被人篡改。
signature
JWT的第三部分叫签证信息,主要用于辨真伪,防篡改。签证信息使用加密算法生成,公式:
secret_key = "秘钥" # 只保存服务端,不能外泄
signature = SHA256(base64.b64encode(header) + "." +base64.b64encode(payload),secret_key)
python代码实现过程:
import sys, json, base64, time, hmacif __name__ == '__main__':# 头部data = {'typ': 'JWT', 'alg': 'HS256'}header = base64.b64encode(json.dumps(data).encode()).decode()# 载荷data = {"sub": "1234567890", "exp": "3422335555", "name": "John Doe", "admin": True,"info": "232323ssdgerere3335dssss"}payload = base64.b64encode(json.dumps(data).encode()).decode()# 签证,生成jwt token 提供给客户端# from django.conf import settings# secret = settings.SECRET_KEYsecret = 'django-insecure-(_+qtd5edmhm%2rdsg+qc3wi@s_k*3cbk-+k2gpg3@qx)z6r+p'sign = base64.b64encode(f"{header}.{payload}".encode())signature = base64.b64encode(hmac.digest(secret.encode(), sign, digest="sha256")).decode()jwt = f"f{header}.{payload}.{signature}"print(jwt)# 将这三部分用`.`连接成一个完整的字符串,构成了最终的jwt:# feyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJleHAiOiAiMzQyMjMzNTU1NSIsICJuYW1lIjogIkpvaG4gRG9lIiwgImFkbWluIjogdHJ1ZSwgImluZm8iOiAiMjMyMzIzc3NkZ2VyZXJlMzMzNWRzc3NzIn0=.3OnGXAx5wWA5AjxyewICSn5Hirz1tXfzxOc4tns4elM=
注意:
secret是保存在服务器端的,jwt的签发生成代码也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,
所以它应该是服务端的私钥,在任何场景下都不应该流露出去,而且应该在每次服务端更新维护后及时更新。
一旦第三方得知这个secret, 那就意味着他们绕过服务端伪造jwt了。
优缺点
优点:
- 实现分布式集群的单点登陆非常方便
- Token实际保存在客户端,所以我们可以分担服务端的存储压力。
- jwt不仅可用于认证,还可用于信息交换。善用JWT有助于减少服务器请求数据库的次数,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
缺点:
- jwt保存在客户端,我们服务端只认jwt,不识别客户端。
- 解决方案1. 设置客户端唯一登陆
- 解决方案2. 绑定客户端的标记符和IP,机器码
- jwt可以设置过期时间,但是因为jwt保存在了客户端,所以对于过期时间不好调整,一旦签发不可控。
- 解决方案1:设置短有效期,例如:30分、15分钟、10分钟之类。
- 解决方案2:生成jwt的时候,提供给客户端之前先在内存(一般使用内存数据库redis,而不是变量)备份jwt,每次用户访问需要登录身份数据时,把token去内存中验证一样。
使用jwt实现认证流程
所谓的认证流程,实际上就是用户登录的过程。
python代码实现认证流程,代码:
import sys, json, base64, time, hmacif __name__ == '__main__':# 模拟客户端提交的tokenclient_token = "feyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJleHAiOiAiMzQyMjMzNTU1NSIsICJuYW1lIjogIkpvaG4gRG9lIiwgImFkbWluIjogdHJ1ZSwgImluZm8iOiAiMjMyMzIzc3NkZ2VyZXJlMzMzNWRzc3NzIn0=.3OnGXAx5wWA5AjxyewICSn5Hirz1tXfzxOc4tns4elM="# 把客户端提交的token分割成三段:头部、载荷、签证header, payload, signature = client_token.split(".")# 验证是否过期了,先基于base64,接着使用json解码,提供载荷中的过期时间进行比较payload_data = json.loads(base64.b64decode(payload.encode()))exp = int(payload_data.get("exp", 0))now = int(time.time())if exp < now:print("token已经过期!")sys.exit() # 退出程序,实际开发中,应该时响应代码给客户端,不会继续往下执行了。secret = "django-insecure-(_+qtd5edmhm%2rdsg+qc3wi@s_k*3cbk-+k2gpg3@qx)z6r+p"# 与生成token时一样的秘钥和数据,再次生成一个签证new_signature = hmac.digest(secret.encode(), sign, digest="sha256")# 拿客户端提交上面的token中的签证进行base64解码得到原始的签证signature = base64.b64decode(signature)# 通过compare_digest比较两者是否吻合if hmac.compare_digest(signature, new_signature):print("认证通过")else:print("认证失败,token被串改!")
基本使用
开发中除非找不到,否则我们可以直接使用第三方已经开源的模块来完成相关的功能。大部分要求使用第三方模块是必须star数量>150。
依赖库安装
# python-jose 用于生成和检验JWT令牌
pip install jwt
pip install python-jose
JWT基本使用
生成一个随机的密钥,用于对JWT令牌进行签名加密的。终端执行命令如下:
openssl rand -hex 32
# eac77e4e9a9a767b792779132e84ea37b1f4c31bec56714607f617a3fbdfbd53
创建JWT需要的相关配置项,settings.py
,代码:
# 加密数据所使用的秘钥[盐值]
SECRET_KEY = "eac77e4e9a9a767b792779132e84ea37b1f4c31bec56714607f617a3fbdfbd53"
# 设定JWT令牌签名算法
ALGORITHM = "HS256"
# 设置令牌过期时间变量(单位:秒)
ACCESS_TOKEN_EXPIRE_MINUTES = 30 * 60
创建JWT工具类,utils.py
,代码:
from typing import Optional
from datetime import timedelta, datetime
import settings
from jose import jwt
import uuidclass JWT(object):JWTError = jwt.JWTErrorExpiredSignatureError = jwt.ExpiredSignatureErrordef create_token(self, data: dict, expire_time: Optional[timedelta] = None):"""生成Token:param data: 需要进行JWT令牌加密的用户信息(解密的时候会用到):param expire_time: 令牌有效期,单位:秒:return: token"""now_time = datetime.utcnow()if expire_time:expire = now_time + timedelta(seconds=expire_time)else:expire = now_time + timedelta(seconds=settings.ACCESS_TOKEN_EXPIRE_TIME)payload = {"exp": expire,"iat": now_time,"nbf": now_time,"jti": str(uuid.uuid4())}payload.update(data)token = jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.ALGORITHM)return tokendef verify_token(self, token: str) -> dict:"""验证token:param token: 客户端发送过来的token:return: 返回用户信息"""payload = jwt.decode(token, settings.SECRET_KEY, algorithms=settings.ALGORITHM)return payloadif __name__ == '__main__':"""密码加密与验证"""# hashing = Hashing()# hashed_pwd = hashing.hash("123456")# print(hashed_pwd) # 加密后要保存到数据库中的哈希串# # 把原密码和加密后的哈希串进行配对,验证通过则返回结果为True# ret = hashing.verify("123456", hashed_pwd)# print(ret)"""JWT"""jwt_tool = JWT()try:# 正确使用token = jwt_tool.create_token({'username': 'admin', 'sex': True})print(token)data = jwt_tool.verify_token(token)print(data)# # 因为Token过期导致验证失败# token = jwt_tool.create_token({'username': 'admin', 'sex': True}, -300)# print(token)# data = jwt_tool.verify_token(token)# print(data)# # 因为Token被串改导致验证失败# token = jwt_tool.create_token({'username': 'admin', 'sex': True})# print(token)# data = jwt_tool.verify_token(token[:-1])# print(data)except (jwt_tool.ExpiredSignatureError, jwt_tool.JWTError) as e:print("验证失败,", e)
基于自定义中间件创建JWT中间件实现用户身份认证
async def jwt_middleware(request: Request, call_next):try:token: str = request.headers["Authorization"].split()[1]payload = jwt_took.verify(token)id: str = payload.get("id")# 查询数据库,是否存在当前用户user = await models.User.filter(id=id).first(id)if user is None:raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials")request.user = userexcept (jwt_tool.ExpiredSignatureError, jwt_tool.JWTError):raise HTTPException(status_code=HTTP_401_UNAUTHORIZED, detail="Invalid authentication credentials")response = await call_next(request)return response
注册JWT中间件,代码:
app.add_middleware(jwt_middleware)
相关文章:

jwt认证课件讲解
JWT 基本概念 在用户登录后,我们需要在不同请求之间记录用户的登录状态,常用方式一般有三种:Cookie,Session和Token。 这里我们使用第三种Token令牌方式来实现认证鉴权,采用Json Web Token认证机制(简称…...

【判断推理】逻辑基础
1.1 命题 用语言、符号或者式子表达的,可以判断真假的陈述句称为命题,一般写为 若p,则q 真命题:判断为真的语句假命题:判断为假的语句 eg1:小张是中国人(若是小张,则是中国人&#…...

AcWing 655:天数转换 ← 整除、求余
【题目来源】https://www.acwing.com/problem/content/657/【题目描述】 读取对应于一个人的年龄(以天为单位)的整数值,并转化为年,月和日表示方式输出,年、月、日分别对应 ano(s), mes(es), dia(s)。 注意:…...

【解决办法】git clone报错unable to access ‘xxx‘: SSL certificate problem:
使用git clone 时报错unable to access xxx: SSL certificate problem: 这个报错通常是由于SSL证书问题引起的。通常可以按照以下步骤进行排查: 检查网络连接:确保你的网络连接正常,可以访问互联网。尝试使用其他网站或工具测试网络连接是否正…...

算法笔记(十三)——BFS 解决最短路问题
文章目录 迷宫中离入口最近的出口最小基因变化单词接龙为高尔夫比赛砍树 BFS 解决最短路问题 BFS(广度优先搜索) 是解决最短路径问题的一种常见算法。在这种情况下,我们通常使用BFS来查找从一个起始点到目标点的最短路径。 迷宫中离入口最近的出口 题目:…...

Android 简单实现联系人列表+字母索引联动效果
效果如上图。 Main Ideas 左右两个列表左列表展示人员数据,含有姓氏首字母的 header item右列表是一个全由姓氏首字母组成的索引列表,点击某个item,展示一个气泡组件(它会自动延时关闭), 左列表滚动并显示与点击的索引列表item …...

自动驾驶-问题笔记-待解决
参考线的平滑方法 参考线平滑算法主要有三种: 离散点平滑;螺旋曲线平滑;多项式平滑; 参考链接:参考线平滑 对于平滑方法,一直不太理解平滑、拟合以及滤波三者的作用与区别; 规划的起点&#x…...

在掌控板中加载人教版信息科技教学指南中的educore库
掌控板中加载educore库 人教信息科技数字资源平台(https://ebook.mypep.cn/free)中的《信息科技教学指南硬件编程代码说明》文件中提到“本程序说明主要供教学参考。需要可编程主控板须支持运行MicroPython 脚本程序。希望有更多的主控板在固件中支持ed…...

关于CSS Grid布局
关于CSS Grid布局 实际效果参考 参考代码 <template><view class"baseInfo"><up-image class"cover" height"160rpx" width"120rpx" :src"bookInfo.cover"><template #error><view style"…...

初始爬虫12(反爬与反反爬)
学到这里,已经可以开始实战项目了,多去爬虫,了解熟悉反爬,然后自己总结出一套方法怎么做。 1.服务器反爬的原因 服务器反爬的原因 总结: 1.爬虫占总PV较高,浪费资源 2.资源被批量抓走,丧失竞争力…...

成像基础 -- 最大对焦清晰的物距计算
最大对焦清晰的物距计算 1. 基本概念 最大对焦清晰的物距通常与景深(Depth of Field, DOF)相关,尤其是无穷远处的物体可以被清晰对焦到的距离,称为超焦距(Hyperfocal Distance)。通过计算超焦距ÿ…...

win10服务器启动且未登录时自动启动程序
场景:公司服务器安装了几个程序,当服务器断电重启之后希望程序能自动打开,而不需要手动登录服务器打开。 因为软件是自己开发的所以安全方面这里没有考虑。 1.打开服务器管理器,点击工具,选择任务计划程序 2.在任务计…...

算法专题四: 前缀和
目录 1. 前缀和2. 二维前缀和3. 寻找数组的中心下标4. 除自身以外数组的乘积5. 和为k的子数组6. 和可被K整除的子数组7. 连续数组8. 矩阵区域和 博客主页:酷酷学!!! 感谢关注~ 1. 前缀和 算法思路: 根据题意, 创建一个前缀和数组, dp[i] dp[i -1] arr[i], 再使用前缀和数组,…...

【Linux】基础IO(文件描述符、缓冲区、重定向)
🌈个人主页:秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343🔥 系列专栏:https://blog.csdn.net/qinjh_/category_12625432.html 目录 前言 C文件IO相关操作 系统文件I/O open open函数返回值 文件描述符fd re…...

一篇文章快速学会docker容器技术
目录 一、Docker简介及部署方法 1.1Docker简介 1.1.1什么是docker 1.1.2 docker在企业中的应用场景 1.1.3 docker与虚拟化的对比 1.1.4 docker的优势 二 、部署docker 2.1 容器工作方法 2.2 部署第一个容器 2.2.1 配置软件仓库 2.2.2 安装docker-ce并启动服务 2.2.…...

【MySQL】使用 JDBC 连接数据库
文章目录 前言1. 认识 JDBC1.1 概念1.2 好处 2. 使用 JDBC2.1 安装数据驱动包2.2 把 jar 包导入到项目中2.3 代码编写2.4 测试结果 3. 代码优化4. 源码展示结语 前言 在 MySQL 系列中,我们介绍了很多内容,包括但不限于建库建表,增删查改等等…...

数据结构与算法笔记:概念与leetcode练习题
1、数组Array 时间复杂度 数组访问:O(1) 数组搜索:O(N) 数组插入:O(N) 数组删除:O(N) 特点 适合读,不适合写 数组常用操作 # 1、创建数组 a [] # 2、尾部添加元素 a.append(1) a.append(2) a.append(3) # 3、…...

十大时间序列预测模型
目录 1. 自回归模型 原理 核心公式 推导过程: 完整案例 2. 移动平均模型 原理 核心公式 推导过程: 完整案例 3. 自回归移动平均模型 原理 核心公式 推导过程: 完整案例 4. 自回归积分移动平均模型 原理 核心公式 推导过程 完整案例 5. 季节性自回归积分…...

G2O 通过工厂函数类 OptimizationAlgorithmFactory 来生成固定搭配的优化算法
OptimizationAlgorithmFactory 类位于 optimization_algorithm_factory.h //***g2o源码 g2o/g2o/core/optimization_algorithm_factory.h ***// /*** \brief create solvers based on their short name** Factory to allocate solvers based on their short name.* The Factor…...

手机USB连接不显示内部设备,设备管理器显示“MTP”感叹号,解决方案
进入小米驱动下载界面,等小米驱动下载完成后,解压此驱动文件压缩包。 5、小米USB驱动安装方法:右击“计算机”,从弹出的右键菜单中选择“管理”项进入。 6、在打开的“计算机管理”界面中,展开“设备管理器”项&…...

SpringBootWeb快速入门!详解如何创建一个简单的SpringBoot项目?
在现代Web开发中,SpringBoot以其简化的配置和快速的开发效率而受到广大开发者的青睐。本篇文章将带领你从零开始,搭建一个基于SpringBoot的简单Web应用~ 一、前提准备 想要创建一个SpringBoot项目,需要做如下准备: idea集成开发…...

RabbitMQ 入门到精通指南
RabbitMQ 是一种开源消息代理软件,基于 AMQP(高级消息队列协议)构建,用于异步传输数据,帮助我们解耦系统、削峰流量、处理高并发。本指南将详细介绍 RabbitMQ 的架构设计、使用场景、安装步骤以及一些高级应用…...

ARM base instruction -- movz
Move wide with zero moves an optionally-shifted 16-bit immediate value to a register. 用零移动宽值将可选移位的16位即时值移动到寄存器。即把立即数移动寄存器前先把寄存器清零。 32-bit variant MOVZ <Wd>, #<imm>{, LSL #<shift>} 64-bit var…...

安装jdk安装开发环境与maven
1.下载maven 链接: https://pan.baidu.com/s/1gTmIWBFBdIQob0cqGG3E_Q 提取码: 42ck,apache-maven-3.8.4-bin.zip 2.安装java jdk yum install -y java-1.8.0-openjdk-devel 3.在/opt目录下新建目录 mkdir /opt/maven 4.将apache-maven-3.8.4-bin.zip上传到/opt/ma…...

openpnp - 图像传送方向要在高级校正之前设置好
文章目录 openpnp - 图像传送方向要在高级校正之前设置好笔记图像传送方向的确定END openpnp - 图像传送方向要在高级校正之前设置好 笔记 图像传送方向和JOG面板的移动控制和实际设备的顶部摄像头/底部摄像头要一致,这样才能和贴板子时的实际操作方向对应起来。 …...

数据库建表规范【记录】
建表规约 【强制】创建表时必须显式指定表存储引擎类型,如无特殊需求,一律为InnoDB。 【强制】必须有行数据的创建时间字段create_date和最后更新时间字段edit_date。 【强制】自增主键命名必须是id,关联表外键命名xxyyzz_id;业务…...

css的动画属性
CSS动画属性是CSS3的一个重要特性,它允许你创建平滑的过渡效果,增强用户的交互体验。CSS动画可以通过keyframes规则和animation属性来创建。 animation属性 animation属性是一个简写属性,用于设置动画的多个属性,包括动画名称、…...

【Ubuntu】PlantUML工具 | 安装 | 语法 | 使用工具画序列图
🌱 PlantUML是一个通用性很强的工具,可以快速、直接地创建各种图表。 目录 1 安装 2 使用PlantUML画序列图 ① 语法 ②示例和效果 利用简单直观的语言,用户可以毫不费力地绘制各种类型的图表。PlantUML 是一个开源项目,支持快速绘制:• 时序图• 用例图• 类图• 对...

微信步数C++
题目: 样例解释: 【样例 #1 解释】 从 (1,1) 出发将走 2 步,从 (1,2) 出发将走 4 步,从 (1,3) 出发将走 4 步。 从 (2,1) 出发将走 2 步,从 (2,2) 出发将走 3 步,从 (2,3) 出发将走 3 步。 从 (3,1) 出发将…...

AI写作工具大比拼:揭秘Claude的神秘魅力以及如何订阅Claude
AI写作困境与Claude的惊喜表现 最近有很多朋友在吐槽AI写的文章不太行,我一看他的要求写的很清楚,已经把提示词都用到位了,例如:写作背景、写作要求等,都有具体写出来。但文章阅读起来就是欠缺点啥。 你们有没有遇到…...