SpringSecurity + jwt + vue2 实现权限管理 , 前端Cookie.set() 设置jwt token无效问题(已解决)

news/2024/7/10 3:09:48 标签: 前端, 状态模式, vue

问题描述

今天也是日常写程序的一天 , 还是那个熟悉的IDEA , 还是那个熟悉的Chrome浏览器 , 还是那个熟悉的网站 , 当我准备登录系统进行登录的时候 , 发现会直接重定向到登录页 , 后端也没有报错 , 前端也没有报错 , 于是我得脸上又多了一张痛苦面具 , 紧接着在前端疯狂debug…寻找问题 , 我前端登录的部分逻辑是这样的 :

1.登录成功之后 , 后端会响应一个jwt token , 这个jwt token的载荷有角色、权限、用户等信息
2.然后我会判断响应状态码 , 如果是200的话 , 就使用 Cookies.set(TokenKey, token , {expires : val}) 将jwt token存到cookie中 ,如果不是200的话 ,弹出错误消息提示
3.登录成功之后 ,会有一个js文件判断是否可以从cookie获取道token ,如果可以获取到 ,正常路由 , 然后跳转页面 , 如果获取不到的话 , 然后进行重定向到登录页面

这就导致我非常的奇怪 ,后端接口也没有问题 ,jwt token也响应到前端了,并且前端debug的时候也可以拿到 ,但就是**Cookies.set(TokenKey, token , {expires : val})**代码执行完毕之后 ,我f12看了一下cookie ,尽然没有存进去? 瞬间懵逼 , 因为昨天还是好好的 ,唯一就动了菜单表的数据 ,然后我又恢复了一下菜单表 , 发现又可以了 , 紧接着又是一系列的数据比对操作 …以为是数据的问题
在这里插入图片描述

然后还没有找到问题 , 于是我就换了一下思路 , 对比了一下可以登录和不可以登录的两个jwt token , 发现长度不一样 ,于是手动在浏览器添加了一下jwt token,发现报错,这个时候问题也就出来了,由于jwt token中的载荷包含了角色、权限、用户等信息,角色和用户的数据都很小 ,只剩下权限了,而我的权限是再菜单表中的,昨天又只动了菜单表的数据 :

所以问题就是 , jwt生成token的长度是和载荷有关系的,由于昨天加了菜单表的数据 ,导致了jwt载荷比较大 , 从而生成的jwt token 也比较大 ,所以再使用Cookies.set(TokenKey, token , {expires : val}) 将token放入cookie时无效

知道问题之后我的痛苦面具也就没了 ,解决问题就好说了 , 下面是解决办法 :

解决办法

使用压缩算法将jwt的载荷数据进行压缩 ,解析jwt token的时候先将载荷进行解压缩:

代码

	/**
	 * 将数据进行压缩
	 * @param data 数据
	 * @return 压缩之后的结果
	 */
	private String compress(String data) {
		try {
			byte[] input = data.getBytes("UTF-8");
			byte[] output = new byte[input.length];
			Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
			deflater.setInput(input);
			deflater.finish();
			int compressedDataLength = deflater.deflate(output);
			byte[] result = new byte[compressedDataLength];
			System.arraycopy(output, 0, result, 0, compressedDataLength);
			return new String(result, "ISO-8859-1");
		} catch (Exception e) {
			throw new RuntimeException("Failed to compress data", e);
		}
	}

	/**
	 * 将压缩之后的数据进行解压
	 * @param compressedData 需要解压的数据
	 * @return 解压之后的数据
	 */
	private String decompress(String compressedData) {
		try {
			byte[] input = compressedData.getBytes("ISO-8859-1");
			byte[] output = new byte[input.length * 2];
			Inflater inflater = new Inflater();
			inflater.setInput(input);
			int decompressedDataLength = inflater.inflate(output);
			byte[] result = new byte[decompressedDataLength];
			System.arraycopy(output, 0, result, 0, decompressedDataLength);
			return new String(result, "UTF-8");
		} catch (Exception e) {
			throw new RuntimeException("Failed to decompress data", e);
		}
	}

使用

这里是创建jwt token的代码 ,解析jwt token的代码也是类似

	/**
	 * 创建JWT
	 *
	 * @param rememberMe  记住我
	 * @param id          用户id
	 * @param subject     用户名
	 * @param roles       用户角色
	 * @param authorities 用户权限
	 * @return {@link String }
	 */
	public String createJWT(Boolean rememberMe, String id, String subject, List<String> roles, Collection<? extends GrantedAuthority> authorities) {
		Date now = new Date();
		Gson gson = new Gson();
		//生成JWT的时间
		long nowMillis = System.currentTimeMillis();
		// 生成加密key
		SecretKey key = generalKey();

		String compress = compress(gson.toJson(authorities));

		// 为payload添加各种标准声明和私有声明了
		JwtBuilder builder = Jwts.builder()
				// 设置jti(JWT ID):是JWT的唯一标识,从而回避重放攻击。
				.setId(id)
				// sub代表这个JWT的主体,即它的所有人。
				.setSubject(subject)
				// jwt签收者
				.setIssuedAt(now)
				// 设置签名使用的签名算法和签名使用的秘钥
				.signWith(SignatureAlgorithm.HS256, key)
				// 创建Payload
				.claim("roles", roles)
				.claim("authorities", compress);

		// 设置过期时间
		long ttlMillis = rememberMe ? Constants.JWT_REMEMBER : Constants.JWT_TTL;
		if (ttlMillis > 0) {
			long expMillis = nowMillis + ttlMillis;
			Date exp = new Date(expMillis);
			builder.setExpiration(exp);
		}

		String jwt = builder.compact();
		// 将生成的JWT保存至Redis
		stringRedisTemplate.opsForValue()
				.set(Constants.REDIS_JWT_KEY_PREFIX + subject, jwt, ttlMillis, TimeUnit.MILLISECONDS);
		return jwt;
	}

到此,问题就解决啦 , 可能编程就是这样 ,编程的过程中会时而遇到困难和挫折,这是相当正常的。同时它是一个充满挑战和解决问题的过程,但也同样带来了许多乐趣和成就感。


http://www.niftyadmin.cn/n/5083123.html

相关文章

docker compose的安装和使用

docker-copose 介绍 docker-compose 是一个容器编排工具&#xff08;自动化部署、管理&#xff09;; 它用来在单台 Linux 服务器上运行多个 Docker 容器; docker-compose 使用YAML文件来配置所有需要运行的 Docker 容器&#xff0c;该 YAML 文件的默认名称为 docker-compose.…

从数据到决策:企业投资信息查询API的关键作用

前言 在现代商业环境中&#xff0c;数据是一项无价的资产。企业不仅需要访问大量数据&#xff0c;还需要将这些数据转化为有用的见解&#xff0c;以支持战略决策。对于企业投资而言&#xff0c;准确的信息和实时的市场数据至关重要。在这个信息时代&#xff0c;企业投资信息查…

python学习笔记3-dictionary和分词

题目链接 words {} 声明一个字典words.get(w, 0) 查找w的分值&#xff0c;若未找到则返回0A.append()用于向列表追加元素A.sort()按照第一个元素和第二个元素的大小顺序对列表排序A[:k]表示前k个元素 class Solution:def topStudents(self, positive_feedback: List[str], n…

html与css知识点

html 元素分类 块级元素 1.独占一行&#xff0c;宽度为父元素宽度的100% 2.可以设置宽高 常见块级元素 h1~h6 div ul ol li dl dt dd table form header footer section nav article aside 行内元素 1.一行显示多个 2.不能设置宽高&#xff0c;宽高由元素内容撑开 常见行内…

使用 Eziriz .NET Reactor 对c#程序加密

我目前测试过好几个c#加密软件。效果很多时候是加密后程序执行错误&#xff0c;或者字段找不到的现象 遇到这个加密软件用了一段时间都很正常&#xff0c;分享一下使用流程 破解版本自行百度。有钱的支持正版&#xff0c;我用的是 Eziriz .NET Reactor 6.8.0 第一步 安装 Ezi…

4+内质网应激+预后模型教你如何应用到自己的生信分析研究中。

今天给同学们分享一篇内质网应激预后模型的生信文章“Characteristics of endoplasmic reticulum stress in colorectal cancer for predicting prognosis and developing treatment options”&#xff0c;这篇文章于2023年3月31日发表在Cancer Med期刊上&#xff0c;影响因子为…

Kotlin-Java 互操作指南

官网地址 https://developer.android.google.cn/kotlin/interop?hlzh-cn 脑图

LSM Tree 深度解析

我们将深入探讨日志结构合并树&#xff0c;也称为LSM Tree&#xff1a;这是许多高度可扩展的NoSQL分布式键值型数据库的基础数据结构&#xff0c;例如Amazon的DynamoDB、Cassandra和ScyllaDB。这些数据库的设计被认为支持比传统关系数据库更高的写入速率。我们将看到LSM Tree如…