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

问题描述

今天也是日常写程序的一天 , 还是那个熟悉的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的时候先将载荷进行解压缩:

代码

java 复制代码
	/**
	 * 将数据进行压缩
	 * @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的代码也是类似

java 复制代码
	/**
	 * 创建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;
	}

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

相关推荐
我要洋人死13 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人25 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人25 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR30 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香32 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969335 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai41 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#