我不应该用JWT的!

news/2024/9/13 11:20:41/文章来源:https://www.cnblogs.com/wlovet/p/18303453

一、前言

大家好呀,我是summo,之前有自学过Shrio框架,网上一搜就有SpringBoot整合Shrio+ JWT的文章,我是在学习Shrio框架的时候顺带学的JWT。后来我还看见有很多博主专门写文章介绍JWT,说这个东西的优点很多,安全性好、去中心化、方便啥的,我就把JWT也应用在我们自己的系统中了。但最近发现这玩意越来越让我觉得别扭,总感觉哪里不太对劲,重新审查我的登录认证逻辑之后才发现:我不应该用JWT的!

这里我用一句解释不该用的原因,省得浪费大家的时间:我的系统有Redis,而且还用Redis存了JWT,随着系统升级,JWT越来越像普通Token!
明白原理的同学可能心中暗笑,直接跳过看下一篇了,不明白原理的同学,可以看看这个四不像是怎么被我搭出来的。

二、JWT是什么?

看我文章的有很多大神,也有一些小白,所以为了不让小白们看的云里雾里,我还是有必要介绍一些基本原理。JWT是 JSON Web Token 的缩写,可以对JSON对象进行编码(加密),并通过这个编码传递信息。

1. JWT的结构

(1)头部(Header)

头部通常由两部分组成,即令牌的类型(typ)和所使用的算法(alg)。例如,一个头部可能是 {"alg": "HS256", "typ": "JWT"},表示使用 HMAC SHA-256 算法对令牌进行签名。

(2)载荷(Payload)

载荷包含了 JWT 的声明信息,用于描述令牌的相关内容。载荷可以包含标准声明(例如:发行者、主题、过期时间等),也可以包含自定义声明。例如,一个载荷可能是 {"sub": "1234567890", "name": "John Doe", "exp": 1516239022}。

(3)签名(Signature)

签名用于验证令牌的完整性和真实性。签名通常由头部、载荷和密钥一起计算而得。验证者可以使用相同的密钥重新计算签名,并将结果与令牌中的签名进行比较,以确认令牌的真实性。

2. SpringBoot使用JWT

(1)maven引入

<!-- jwt -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.8.2</version>
</dependency>

(2)代码示例


import java.util.Date;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;@Slf4j
public class JWTUtil {/*** 过期时间*/private static final long EXPIRE_TIME = 60 * 1000;/*** 校验 token是否正确** @param token  密钥* @param secret 用户的密码* @return 是否正确*/public static boolean verify(String token, String username, String secret) {try {Algorithm algorithm = Algorithm.HMAC256(secret);JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();verifier.verify(token);log.info("token is valid");return true;} catch (Exception e) {log.info("token is invalid{}", e.getMessage());return false;}}/*** 从 token中获取用户名** @return token中包含的用户名*/public static String getUsername(String token) {try {DecodedJWT jwt = JWT.decode(token);return jwt.getClaim("username").asString();} catch (JWTDecodeException e) {log.error("error:{}", e.getMessage());return null;}}/*** 生成 token** @param username 用户名* @param secret   用户的密码* @return token*/public static String sign(String username, String secret) {try {username = StringUtils.lowerCase(username);Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);Algorithm algorithm = Algorithm.HMAC256(secret);return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);} catch (Exception e) {log.error("error:{}", e);return null;}}public static void main(String[] args) {//对数据进行加密String token = sign("zhangshan", "123456");System.out.println(token);//对数据进行解密System.out.println(getUsername(token));}
}

运行一下

JWT还是很简单的,一学就会,很多博主在介绍它的时候都会说它安全、方便、去中心化等等,然后强烈推荐大家使用。但这里我要就要给大家泼冷水了,学是肯定要学的,用就需要看情况了,不能别人说它好,你就无脑用,然后用成一个四不像。至于我为什么说我用来是四不像,接着看!

三、JWT vs Token+Redis

在设计no session系统时,有两种可选方案:JWT与Token+Redis。

1. 原理简介

  • JWT: 生成并发给客户端之后,后台是不用存储,客户端访问时会验证其签名、过期时间等再取出里面的信息(如username),再使用该信息直接查询用户信息完成登录验证。jwt自带签名、过期等校验,后台不用存储,缺陷是一旦下发,服务后台无法拒绝携带该jwt的请求(如踢除用户);

  • Token+Redis: 是自己生成个32位的key,value为用户信息,访问时判断redis里是否有该token,如果有,则加载该用户信息完成登录。服务需要存储下发的每个token及对应的value,维持其过期时间,好处是随时可以删除某个token,阻断该token继续使用。

2. 两种方案的优缺点

(1)去中心化的JWT

优点

  1. 去中心化,便于分布式系统使用
  2. 基本信息可以直接放在token中。 username,nickname,role
  3. 功能权限较少的话,可以直接放在token中。用bit位表示用户所具有的功能权限

缺点

  1. 服务端不能主动让token失效

(2)中心化的Redis+Token

优点

  1. 服务端可以主动让token失效

缺点

  1. 依赖内存或redis存储。
  2. 分布式系统的话,需要redis调用增加了系统复杂性。

光看优缺点的话,JWT优点还比Redis+Token多,在小白时期的我一看:好家伙,JWT这么多优点,用它准没错,看来简历上又可以加上一笔了!

四、我的方案

想法是美好的,但现实是残酷的,为什么我会觉得越来越别扭,先上一张流程图,让大家看看我在业务中是怎么做的,如下:

上面的方案是JWT或者Redis+Token,而我的方案是JWT+Redis🤡。和普通的流程相比,我还加了一个加解密流程,因为我觉得JWT数据格式太明显了,一眼就知道是用的是什么认证方式,容易被篡改。你说这个一点用都没有吗?好像还有那么点用,最起码JWT变得更安全了...

1. 别扭原因

(1)多余的加解密流程

虽然给JWT加一下密提高了安全性,但是导致JWT的自带的过期机制失效了,必须得加上Redis的缓存失效机制,在安全和方便的选项中我选择了安全。

(2)系统对用户的操作频繁

因为我们的系统是一个传统的管理端+C端模式,管理员经常给用户增删权限,刚好命中“服务端不能主动让token失效”这一缺陷,这是最大的原因。

(3)JWT随着系统的升级字符越来越长

JWT存储的信息比较少的时候,还只有一两百个字符,但是字段一多,直接变成“小作文”,我现在看着这一段长长的token,头都大。

(4)单点登录使用JWT太不可控了

实现不了单点登录之后的单点退出功能,即用户在一个系统登出,所有相关系统也自动登出,JWT完全不能满足这个需求。

2. 总结一下

写这篇文章我想肯定会有很多人不服,说我不会用就说人家不好用。诚然,我确实不太会用,不然我也不会用JWT到我的系统中来。我也看了很多介绍JWT的文章,都是说原理和优点,很少有说它的应用场景,知乎上有一篇关于jwt与token+redis,哪种方案更好用?的辩论,很激烈,感兴趣的同学可以去看看。

这个帖子里面的大部分人都认为JWT不是一个必要的组件,甚至有人说任何时候都不应该首要考虑JWT,现在的我深感赞同。里面还有不少老哥推荐使用折中方案,也就是上面我的方案:JWT+Redis,不过我总感觉这种用法很别扭,因为一旦上了Redis那和Redis+Token方案还有什么不同,而且JWT还长的多,白白浪费用户的流量。

里面有个老哥的比喻我觉得非常形象,给大家看下

我觉得这个老哥讲的还挺有道理,JWT本身也只是一个token(有点长的token),非要让它满足所有的需求属实是难为它了。但是如果仅仅只是创造一个新品,如意大利面,就开始疯狂吹嘘它无所不能,给小白一些错误的引导,那就不对了,毕竟喜欢吃意大利面的人也不多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/744178.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI 曝新项目「草莓」,提升 AI 推理能力;智谱 AI 开源视频理解模型丨 RTE 开发者日报

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点…

2024-07-15 vue组件发布npm后,再使用,样式不见了?==》查看样式是否在dist包里,有的话应该就是样式没引用

哎,嗯。。。emmm。。。 好,问题就是这样的,最近写了vue组件打算上到npm,然后上是上了,但是样式却没有生效??左上角是组件样式本地调试的截图,可以看到是生效的,右上角的截图是我在别的项目引用了我写的这个库,结果样式却没有生效。 我打包后的文件列表如下: 注意:s…

centos8 内核升级教程 执行安装成功后 reboot

Centos 处理步骤 先设置DNS为114.114.114.114等 CentOS 8 升级内核到 6.9 步骤 **1 查看内核现状版本 4.18** [root@localhost yum.repos.d]# hostnamectl Static hostname: localhost.localdomain Icon name: computer-vm Chassis: vm Machine ID: 1c063b9ed186473e891a2fe6ac…

【笔记】Nmap工具原理探索

学习记录下计网原理的东西【笔记】Nmap工具原理探索 原文章:【THM】Nmap(Nmap工具使用简介)-学习 - Hekeatsll - 博客园 (cnblogs.com) Nmap是一款跨平台的开源端口扫描软件,它用来扫描计算机的开放端口,以确定运行的网络服务,并推断出计算机运行的操作系统 Nmap三种基本扫…

QUIC(更新中... ...)

本文档只记录我个人认为应该着重进行一下笔记的部分。 RFC QUIC 基本内容介绍在RFC 9000,加密的实现在9001,丢包检测和拥塞机制在9002。 简介 是由Google开发的一种基于UDP的传输层协议,旨在提高网络传输的性能和安全性。关键要素:UDP 443端口,将TLS 1.3内置在QUIC协议报文…

论文阅读:使用集合预测网络进行联合实体和关系提取

github代码:http://github.com/DianboWork/SPN4RE 目的从本质上讲,句子中提到的关系三元组是集合的形式,它没有元素之间的内在顺序,并表现出排列不变的特征。(多个三元组的抽取顺序,对抽取结果没有影响) 然而,以前基于 seq2seq 的模型需要事先使用一些启发式全局规则将…

打造个人贴身助理-小白必备AI技能

打造个人贴身助理-小白必备AI技能 将你的公众号接入AI智能体 登录后台开启开发者功能coze 后台创建 bot 登录 Coze 国内官网地址:https://www.coze.cn。点击右上角【开始使用】。 创建智能体 点击左上角【创建Bot】配置选择模型配置人设和插件发布到自己的公众号成功发布进入公…

免费可视化工具如何打造动态销售管理看板?

在这个数据驱动的时代,销售管理不再仅仅依赖于传统的报表和口头汇报,而是越来越倾向于直观、动态的可视化展示。可视化工具的出现,无疑为中小企业乃至大型企业提供了强大的助力,帮助销售团队构建高效、直观的销售管理看板,让数据说话,决策有据可依。今天要说的是,如何利…

jmeter分布式实战

一、原理(jdk和jmeter版本必须一致)二、配置执行机slave 修改配置文件:JMETER_HOME/bin/jmeter.properties 中如下信息即可完成配置执行机远程启动端口(默认为 1099) server_port=1029 server.rmi.localport=1029 server.rmi.ssl.disable改为true 启动执行机服务器: 管理…

Microsoft Office 自定义安装部署工具 | Mocreak

软件简介: Mocreak 是一款一键自动化下载、安装、部署正版 Office 的办公增强工具。该工具完全免费、无广告、绿色、无毒、简约、高效、安全。 软件特点: 一键快速下载、安装、部署最新版 Microsoft Office 软件。提供简约、高效,且可自定义的图形界面,提升部署效率。支持将…

旋转相册

做自己的太阳,成为别人的光!