分布式应用下登录检验解决方案

news/2024/4/28 3:58:58/文章来源:https://blog.csdn.net/qq_30294911/article/details/137028373

优缺点

        JWT 是一个开放标准,它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名。说白了就是通过一定规范来生成token,然后可以通过解密算法逆向解密token,这样就可以获取用户信息。生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库,可以存储在客户端,不占用服务端的内存资源,在前后端分离项目中经常使用。 JWT token可存储在cookie、localstorage和sessionStorage中。

        缺点:

        1)token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息,如用户权限,密码等。

        2)如果没有服务端存储,则不能做登录失效处理,除非服务端改秘钥。

组成部分

JWT由三部分组成:头部(Header)、载荷(Payload)、签名(Signature)。

头部(header):主要是描述签名算法

{"alg": "HS256","typ": "JWT"
}

负载(payload):主要描述是加密对象的信息,如用户的id等,也可以加些规范里面的东西,如iss签发者,exp 过期时间,sub 面向的用户

{"sub": "1234567890","name": "John Doe","admin": true
}

签名(signature):主要是把前面两部分进行加密,防止别人拿到token进行base解密后篡改token

具体实现

依赖引入

<!-- JWT相关 -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.7.0</version>
</dependency>

JWT核心代码:生成Token|解密Token

@Slf4j
public class JWTUtil {/*** 主题*/private static final String SUBJECT = "test";/*** 加密密钥*/private static final String SECRET = "test.com";/*** 令牌前缀*/private static final String TOKEN_PREFIX = "test-study";/*** token过期时间,7天*/private static final long EXPIRED = 1000 * 60 * 60 * 24 * 7;/*** 生成token** @param loginUser* @return*/public static String geneJsonWebToken(LoginUser loginUser) {if (loginUser == null) {throw new NullPointerException();}String token = Jwts.builder().setSubject(SUBJECT)
//                配置payload(负载).claim("head_img", loginUser.getHeadImg()).claim("account_no", loginUser.getAccountNo()).claim("username", loginUser.getUsername()).claim("mail", loginUser.getMail()).claim("phone", loginUser.getPhone()).claim("auth", loginUser.getAuth()).setIssuedAt(new Date()).setExpiration(new Date(CommonUtil.getCurrentTimestamp() + EXPIRED)).signWith(SignatureAlgorithm.HS256, SECRET).compact();token = TOKEN_PREFIX + token;return token;} /*** 解密JWT* @param token* @return*/public static Claims claimsJWT(String token){try {Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();return claims;} catch (Exception e) {log.error("解密失败");return null;}}
}

 登录成功返回token

//生成token令牌
LoginUser userDTO = new LoginUser();
BeanUtils.copyProperties(userDO, userDTO);
String token = JWTUtil.geneJsonWebToken(userDTO);
return JsonData.buildSuccess(token);

 登录拦截器

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {/*** 这段代码定义了一个静态的 ThreadLocal 对象 threadLocal,它的泛型参数是 LoginUser 类型,表示要存储的线程本地变量类型是 LoginUser。** 在代码的第二行中,使用 threadLocal.set(loginUser) 方法将当前线程的 threadLocal 变量副本设置为 loginUser。* 这样,在后续的代码中,当前线程就可以通过 threadLocal.get() 方法获取到自己的 loginUser 变量副本,而不会受到其他线程的影响。** 通常情况下,我们会将一些需要在整个应用程序中共享的数据存储在一个全局的变量中,* 但是这样会存在线程安全问题。使用 ThreadLocal 可以解决这个问题,每个线程都有自己的变量副本,* 不会互相干扰。在这段代码中,使用 ThreadLocal 存储了当前线程的登录用户信息,* 以便在后续处理请求时能够方便地获取到该信息。*/public static ThreadLocal<LoginUser> threadLocal=new ThreadLocal<>();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (Request.HttpMethod.OPTIONS.toString().equalsIgnoreCase(request.getMethod())) {response.setStatus(HttpStatus.NO_CONTENT.value());return true;}String accessToken = request.getHeader("token");if (StringUtils.isBlank(accessToken)) {accessToken = request.getParameter("token");}if (StringUtils.isNotBlank(accessToken)) {
//            token解密Claims claims = JWTUtil.claimsJWT(accessToken);if (claims == null) {//未登录CommonUtil.sendJsonMessage(response, JsonData.buildResult(BizCodeEnum.ACCOUNT_UNLOGIN));return false;}Long accountNo = Long.parseLong(claims.get("account_no").toString());String headImg = (String) claims.get("head_img");String username = (String) claims.get("username");String mail = (String) claims.get("mail");String phone = (String) claims.get("phone");String auth = (String) claims.get("auth");LoginUser loginUser = LoginUser.builder().accountNo(accountNo).auth(auth).phone(phone).headImg(headImg).mail(mail).username(username).build();//request.setAttribute("loginUser",loginUser);//通过ThreadlocalthreadLocal.set(loginUser);return true;}CommonUtil.sendJsonMessage(response,JsonData.buildResult(BizCodeEnum.ACCOUNT_UNLOGIN));return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 释放当前线程的 ThreadLocal 变量副本所占用的内存空间threadLocal.remove();}
}

拦截器配置类

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor())//添加拦截的路径.addPathPatterns("/api/visit_stats/*/**");//排除不拦截
//                .excludePathPatterns("/api/product/*/**");}
}

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

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

相关文章

Java基础语法(二)

前言 Hello&#xff0c;大家好&#xff01;很开心与你们在这里相遇&#xff0c;我是一个喜欢文字、喜欢有趣的灵魂、喜欢探索一切有趣事物的女孩&#xff0c;想与你们共同学习、探索关于IT的相关知识&#xff0c;希望我们可以一路陪伴~ 1. 类型转换 1.1 自动类型转换 什么是自…

RabbitMQ3.x之三_RabbitMQ新建用户及开启远程访问

RabbitMQ3.x之三_RabbitMQ新建用户及开启远程访问 文章目录 RabbitMQ3.x之三_RabbitMQ新建用户及开启远程访问1. guest不能远程访问2. 创建专有用户远程访问RabbitMQ1. 创建用户2. 给用户分配tag(角色)3. 开启远程访问 3. 新用户远程登录 1. guest不能远程访问 在 RabbitMQ 中&…

网络爬虫框架Scrapy的入门使用

Scrapy的入门使用 Scrapy概述引擎&#xff08;Engine&#xff09;调度器&#xff08;Scheduler&#xff09;下载器&#xff08;Downloader&#xff09;SpiderItem Pipeline 基本使用安装scrapy创建项目定义Item数据模型对象创建爬虫(Spider)管道pipeline来保存数据启动爬虫 其他…

利用lidar生成深度图

前言 目前&#xff0c;深度图像的获取方法有&#xff1a;激光雷达深度成像法、计算机立体视觉成像、坐标测量机法、莫尔条纹法、结构光法等。针对深度图像的研究重点主要集中在以下几个方面&#xff1a;深度图像的分割技术&#xff0c;深度图像的边缘检测技术&#xff0c;基于…

python的神奇bug2

今天测试出一个很诡异的bug&#xff0c; 这个错误还真的很难发现 测试1 a [1,10,100] for i in a:print(i)if(i10):a[20,30,-1]一般来说我们在进行迭代时&#xff0c;a这个值时不能改动的&#xff0c;但是现在的问题时如果我不小心给改动了呢&#xff0c;结果如下 也就是说…

文本文件操作

大家好&#xff1a; 衷心希望各位点赞。 您的问题请留在评论区&#xff0c;我会及时回答。 文件操作 程序运行时&#xff0c;产生的数据都是临时数据&#xff0c;程序一旦运行结束都会被释放。通过文件可以将数据持久化。 C中对文件进行操作需要包含头文件<fstream> 文件…

关于深度学习的 PyTorch 项目如何上手分析?从什么地方切入?

文章目录 PyTorch 项目分析1.背景2.分析流程 PyTorch 项目分析 1.背景 当我们拿到一个 PyTorch 的深度学习项目时&#xff0c;应该怎么入手&#xff1f;怎么去查看代码&#xff1f; 2.分析流程 首先阅读对应项目的 README.md 文件。通过阅读 README.md &#xff0c;一般可以…

【Redis面试题】Redis 的大 Key 对持久化有什么影响?

目录 大 Key 对 AOF 日志的影响大 Key 对 AOF 重写和 RDB 的影响总结 Redis 的持久化方式有两种&#xff1a;AOF 日志和 RDB 快照。 所以接下来&#xff0c;针对这两种持久化方式具体分析分析。 大 Key 对 AOF 日志的影响 先说说 AOF 日志三种写回磁盘的策略 Redis 提供了 3 …

记录在项目中引用本地的npm包

1、先把需要的包下载下来&#xff0c;以Photo Sphere Viewer 为引用的npm包、项目以shpereRepo为例子 git clone https://github.com/mistic100/Photo-Sphere-Viewer2、拉下代码后修改之后执行 ./build.sh build.sh #!/usr/bin/env bashyarn run build targetDir"../sh…

HarmonyOS 应用开发之UIAbility组件间交互(设备内)

UIAbility是系统调度的最小单元。在设备内的功能模块之间跳转时&#xff0c;会涉及到启动特定的UIAbility&#xff0c;该UIAbility可以是应用内的其他UIAbility&#xff0c;也可以是其他应用的UIAbility&#xff08;例如启动三方支付UIAbility&#xff09;。 本文将从如下场景…

Etcd 基本入门

1&#xff1a;什么是 Etcd ? Etcd 是 CoreOS 团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。etcd内部采用raft协议作为一致性算法&#xff0c;Etcd基于 Go 语言实现。 名字由来&#xff0c;它源于两个方面&#xff0c;…

面试笔记——MyBatis(执行流程、延迟加载和缓存)

MyBatis 是一个持久层框架&#xff0c;用于简化 Java 应用程序与数据库之间的交互过程。具体而言&#xff0c;它提供了一种将数据库操作映射到 Java 方法的方式&#xff0c;通过 XML 文件或注解配置 SQL 语句与 Java 方法的映射关系。使用 MyBatis&#xff0c;开发人员可以通过…

YOLOV8逐步分解(2)_DetectionTrainer类初始化过程

接上篇文章yolov8逐步分解(1)--默认参数&超参配置文件加载继续讲解。 1. 默认配置文件加载完成后&#xff0c;创建对象trainer时&#xff0c;需要从默认配置中获取类DetectionTrainer初始化所需的参数args&#xff0c;如下所示 def train(cfgDEFAULT_CFG, use_pythonFalse…

Docker-Container

Docker ①什么是容器②为什么需要容器③容器的生命周期容器 OOM容器异常退出容器暂停 ④容器命令清单总览docker createdocker rundocker psdocker logsdocker attachdocker execdocker startdocker stopdocker restartdocker killdocker topdocker statsdocker container insp…

Elasticsearch从入门到精通-07ES底层原理学习

Elasticsearch从入门到精通-07ES底层原理和高级功能 &#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是程序员行走的鱼 &#x1f4d6; 本篇主要介绍和大家一块学习一下ES底层原理包括集群原理、路由原理、分配控制、分配原理、文档分析原理、文档并发安全原理以及一些高…

第十四届蓝桥杯JavaA组省赛真题 - 特殊日期

解题思路&#xff1a; 暴力秒了 public class Main {public static void main(String[] args) {int cnt 0;for (int i 1900; i < 9999; i) {for (int j 1; j < 12; j) {for (int k 1; k < days(i, j); k) {if (sum(i) sum(j) sum(k)) cnt;}}}System.out.print…

算法笔记~—位运算

目录 常见位运算&#xff1a; 1、基础位运算 2、对于一个数n。确定、修改这个数n二进制x位。 3、提取&#xff08;确定&#xff09;一个数n最右侧的1&#xff08;bit&#xff09;与干掉最右侧的1&#xff08;bit&#xff09; 4、异或运算律 5、位运算的优先级&#xff1a…

Qt扫盲-QAssisant 集成其他qch帮助文档

QAssisant 集成其他qch帮助文档 一、概述二、Cmake qch例子1. 下载 Cmake.qch2. 添加qch1. 直接放置于Qt 帮助的目录下2. 在 QAssisant中添加 一、概述 QAssisant是一个很好的帮助文档&#xff0c;他提供了供我们在外部添加新的 qch帮助文档的功能接口&#xff0c;一般有两中添…

百度智能云千帆,产业创新新引擎

本文整理自 3 月 21 日百度副总裁谢广军的主题演讲《百度智能云千帆&#xff0c;产业创新新引擎》。 各位领导、来宾、媒体朋友们&#xff0c;大家上午好。很高兴今天在石景山首钢园&#xff0c;和大家一起沟通和探讨大模型的发展趋势&#xff0c;以及百度最近一段时间的思考和…

为什么Python不适合写游戏?

知乎上有热门个问题&#xff1a;Python 能写游戏吗&#xff1f;有没有什么开源项目&#xff1f; Python可以开发游戏&#xff0c;但不是好的选择 Python作为脚本语言&#xff0c;一般很少用来开发游戏&#xff0c;但也有不少大型游戏有Python的身影&#xff0c;比如&#xff1…