SpringBoot集成JWT

一、 背景

项目需要,自己编写登录和身份校验,于是采用了JWT的方式。

二、实现步骤

2.1 引入JWT组件
 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version> <!-- 使用时请检查最新版本 --></dependency>
2.2 编写JWT工具类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;/*** @author ****** @description JWT 工具类* @date 2024年04月08日 15:45*/
public class JwtTokenUtil {/*** 生成token* @param token存入的值,包括username userfullname  手机号 代理商id  代理商名称* @return*/public static String generateToken(String userToken) {Date now = new Date();Date expiryDate = new Date(now.getTime() + Constants.TOKEN_EXPIRATION);return Jwts.builder().setSubject(userToken).setIssuedAt(now).setExpiration(expiryDate).signWith(SignatureAlgorithm.HS512, Constants.TOKEN_SECRET).compact();}/*** 根据token获得Claims* @param username* @return*/public static Claims getClaimsFromToken(String token) {try {return Jwts.parser().setSigningKey(Constants.TOKEN_SECRET).parseClaimsJws(token).getBody();} catch (Exception e) {return null;}}/*** 根据token获得用户* @param username* @return*/public  static String getUsernameFromToken(String token) {Claims claims = getClaimsFromToken(token);return claims != null ? claims.getSubject() : null;}/*** 校验token是否有效* @param token* @param username* @return*/public static boolean validateToken(String token) {final String usernameFromToken = getUsernameFromToken(token);return (usernameFromToken != null  && !isTokenExpired(token));}/*** token 是否超时* @param token* @return*/private static boolean isTokenExpired(String token) {final Date expiration = getExpirationDateFromToken(token);return expiration.before(new Date());}/*** token 得到token的超时时间* @param token* @return*/private static Date getExpirationDateFromToken(String token) {final Claims claims = getClaimsFromToken(token);return claims.getExpiration();}}
2.3 用户登录生成token
 public ResultBO<String> userLogin(SysUserBO sysUserBO){ResultBO<String> resultBO = new   ResultBO<String>();if(StringUtil.isNullOrEmpty(sysUserBO.getUserName()) ){resultBO.setCode(CommonResult.USER_IS_NOT_NULL.getCode());resultBO.setSuccess(false);resultBO.setMessage("登录失败:请输入用户名");return  resultBO;}if(StringUtil.isNullOrEmpty(sysUserBO.getUserPassWord()) ){resultBO.setCode(CommonResult.USER_IS_NOT_NULL.getCode());resultBO.setSuccess(false);resultBO.setMessage("登录失败:请输入密码");return  resultBO;}// 密码规则:用户账号+用户密码+固定字符串 然后用AES加密String passWord = sysUserBO.getUserName()+sysUserBO.getUserPassWord()+ Constants.PASS_WORD_SECRET;passWord=AesUtil.encrypt(passWord);SysUserDO  sysUserDO = new   SysUserDO();sysUserDO = ModelMapperUtil.map(sysUserBO,SysUserDO.class);sysUserDO.setUserPassWord(passWord);List<SysUserDO> sysUserDOS = sysUserDao.selectUserList(sysUserDO);if(sysUserDOS!=null && sysUserDOS.size()>0 ){// 查询到了用户// 登录成功创建token 将用户相关关键的字段都放入到token里面去TokenUser tokenUser = new TokenUser();tokenUser.setCenterUserId(sysUserDOS.get(0).getCenterUserId());tokenUser.setUserFullName(sysUserDOS.get(0).getUserFullName());tokenUser.setId(sysUserDOS.get(0).getId());tokenUser.setUserName(sysUserDOS.get(0).getUserName());tokenUser.setAgentId(sysUserDOS.get(0).getAgentId());tokenUser.setAgentName(sysUserDOS.get(0).getAgentName());tokenUser.setPhoneNumber(sysUserDOS.get(0).getPhoneNumber());String tokenUserDOStr = FastJsonUtil.toJsonString(tokenUser);String token =  JwtTokenUtil.generateToken(tokenUserDOStr); // sysUserDOS.get(0).getUserName()resultBO.setCode(CommonResult.SUCCESS.getCode());resultBO.setSuccess(true);resultBO.setMessage("登录成功");resultBO.setData(token);}else{// 查询不到数据// 登录失败resultBO.setCode(CommonResult.DATA_NOT_EXISTS_ERROR.getCode());resultBO.setSuccess(false);resultBO.setMessage("登录失败:账号或密码错误");}return  resultBO;}
2.4 编写拦截器校验token
 import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @author ***** @description 自定义拦截器* @date 2024年04月08日 17:05*/@Component
public class MyInterceptor implements HandlerInterceptor {/*** 请求头*/private static final String HEADER_AUTH = "token";/*** 拦截过滤方法* @param request* @param response* @param handler* @return*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {response.setContentType("application/json; charset=utf-8");String prop = request.getRequestURI().substring(request.getContextPath().length());String url =  prop;// 登录和注册等请求不需要令牌// 安全连接,无需拦截配置 一般开放登录方法if (prop.contains("/login/") || prop.contains("/syncUser") ) {return true;}// System.out.println("***********没有被放行的请求*************");// 从请求头里面读取tokenString token = request.getHeader(HEADER_AUTH);if (token == null) {throw new RuntimeException("请求失败,令牌为空");}System.out.println(token);// 解析令牌boolean validateToken = JwtTokenUtil.validateToken(token);if(!validateToken){throw new RuntimeException("请求失败,无效的令牌");}else{try{// 如果是有效的,则解析token里面的user信息提供给接口使用String tokenStr = JwtTokenUtil.getUsernameFromToken(token);TokenUser tokenUser = FastJsonUtil.toObj(tokenStr,TokenUser.class);ContextHolder.setTokenUser(tokenUser);// 将用户信息添加到请求属性中// request.setAttribute("currentUser", tokenUser);return  true;}catch(Exception ex){throw new RuntimeException("请求失败,无效的令牌");}}}
}
2.5 使用ContextHolder给接口调用获取当前登陆人
/*** @author ***** @description token解析用户信息Context类* @date 2024年04月09日 10:59*/
public class ContextHolder {public static ThreadLocal<TokenUser> context = new ThreadLocal<>();public static void setTokenUser(TokenUser tokenUserDO) {context.set(tokenUserDO);}public static TokenUser getTokenUser() {return context.get();}public static void shutdown() {context.remove();}}
2.6 注册拦截器,注意文件放置的位置要跟启动类同一层,这样才能扫描到
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;/*** @author ***8* @description 自定义拦截器注册* @date 2024年04月08日 17:11*/@Configuration
public class InterceptorConfig  implements WebMvcConfigurer {@Resourceprivate MyInterceptor loginInterceptor;@Overridepublic void addInterceptors (InterceptorRegistry registry) {//注册LoginInterceptor拦截器registry.addInterceptor(loginInterceptor);}}
2.7 TokenUser类
@Data
public class TokenUser {/*** 用户id*/private Long id;/*** 用户名(登录账号名)*/private String userName;/*** 代理商id*/private String agentId;/*** 代理商名称*/private String agentName;/*** 用户全名*/private String userFullName;/*** 手机号*/private String phoneNumber;/*** 中心系统 userid*/private String centerUserId;
}

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

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

相关文章

CMake学习笔记(三)区分macro与function

目录 共同点--形式类似 macro的形式 function的形式 不同点 1 输入参数的替换阶段不同 macro function 2 输入参数作用域不同 macro function 共同点--形式类似 macro的形式 macro(宏名 输入参数名).... endmacro() function的形式 function(函数名 输入参数名).…

积分学<3>——定积分的详细定义与可积条件

索引 定积分的详细定义与可积条件Riemann可积定义3.1 Riemann和定义3.2 Riemann可积 定积分定义定义3.3 定积分 定积分定义的扩展定义3.4 Darboux上(下)和引理3.1引理3.2定理3.1 Darboux定理定理3.2 定积分的详细定义与可积条件 Riemann可积 定义3.1 Riemann和 若函数 f ( x…

20232831 2023-2024-2 《网络攻防实践》第5次作业

目录 20232831 2023-2024-2 《网络攻防实践》第5次作业1.实验内容&#xff08;1&#xff09;防火墙配置&#xff08;具体IP配置参考自己的IP设置&#xff09;&#xff08;2&#xff09;动手实践&#xff1a;Snort&#xff08;3&#xff09;分析配置规则 2.实验过程3.学习中遇到…

基于小程序实现的校园失物招领系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

渗透测试概述

渗透测试概述 渗透测试&#xff0c;又称入侵测试或黑盒测试&#xff0c;是一种通过模拟黑客攻击行为来评估计算机系统安全性的方法。其目的在于发现系统中的潜在漏洞&#xff0c;并评估这些漏洞可能带来的风险&#xff0c;从而为系统管理员和安全团队提供改进建议。渗透测试通…

第十二天--二维数组的彻底解刨--地址

1.二维数组我们用父子的地址来称呼二维数组的地址 比如arr[3][4] 这里的arr是二维数组的首地址&#xff0c;也是父数组的首地址&#xff0c;也是子数组的首地址 arr1父数组的地址偏移1&#xff0c;实际上是偏移了4*416个字节 arr[0]是子数组的首地址&#xff0c;arr[0]1是子数…

langchain txt 文档加载,分割

stuff 策略 加载 arXiv 论文&#xff0c;让模型总结前 2000 字 这里采用的是 stuff 策略&#xff0c;也就是将一大段文本。按字数分割成 N 个文本块&#xff0c;又合并成一个大的文本块。 对超大规模不友好&#xff0c;没有区分文档重要性&#xff0c;适合文档量较少场景 i…

安卓刷机fastboot分段传输

win10 fastboot 无法识别&#xff0c;驱动下载地址GitHub - xushuan/google_latest_usb_driver_windows 把inf文件更新到设备管理器驱动更新即可 问题 archive does not contain super_empty.img Sending vbmeta_a (4 KB) OKAY [ 0.117s] Writing …

Springboot项目的测试类书写(速通)

目录 前言1. 单元测试的测试类2. 框架测试的测试类 前言 在实际开发中&#xff0c;如果只是做一个简单的单元测试&#xff08;不涉及端到端、数据库交互、API调用、消息队列处理等&#xff09;&#xff0c;我为了方便一般都是找块儿地方写一个main方法来跑一下就行了&#xff…

Redis中的集群(六)

集群 ASK错误 在进行重新分片期间&#xff0c;源节点向目标节点迁移一个槽的过程中&#xff0c;可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里面&#xff0c;而另一部分键值对则保存在目标节点里面。当客户端向源节点发送一个与数据库有关的命令&#xf…

std::vector的核心框架接口的模拟实现bit::vector

std::vector的核心框架接口的模拟实现bit::vector #pragma once #include<iostream> #include<assert.h> #include<string> #include<algorithm> #include<vector>using std::cout; using std::endl;namespace bit {template<class T>cla…

C中自定义类型——结构体

一.前言 在C语言中&#xff0c;不仅有int、char、short、long等内置类型&#xff0c;C语言还有一种特殊的类型——自定义类型。该类型可以由使用者自己定义&#xff0c;可以解决一些复杂的个体。 二.结构体 2.1结构体的声明 我们在利用结构体的时候一般是用于描述一些有多种…

c++ 类型转换dynamic_cast

在C中&#xff0c;dynamic_cast 是一种用于安全地将指针或引用从一个类类型转换为另一个类类型的运算符。它主要用于在继承层次结构中进行类型转换&#xff0c;并在运行时执行类型检查&#xff0c;以确保转换的安全性。 dynamic_cast 执行以下操作&#xff1a; 1. 它检查 expr…

【SpinalHDL】Scala编程中的var及val

1. var与val区别及相同点 在SpinalHDL中&#xff0c;var 和 val 是两种不同的变量声明方式&#xff0c;它们在用法和语义上有一些区别和相同点&#xff1a; 1. 区别 var&#xff1a;代表可变变量&#xff0c;类似于其他编程语言中的可变变量。使用 var 声明的变量可以在声明…

javaweb配置JSTL

首先配置好javaweb项目。 在网上下载好jakarta-taglibs-standard并解压。 在web/WEB-INF目录下创建lib目录。 在jakarta-taglibs-standard目录下lib目录内的两个.jar文件复制到javaweb项目lib目录下。 将这两个.jar包导入库。 在idea菜单栏找到“文件”并打开&#xff0c;点…

linux磁盘知识学习

文章目录 linux 磁盘阵列知识积累配置RAID方案在Linux中配置RAID在其他设备上配置RAID 确认是什么RAID级别cat /proc/mdstat 输出示例mdadm --detail /dev/md0输出示例 如何确认设备是否做了RAID其他方式fdisklsblkpartedlshwlsscsismartctlblkid 不同命令使用场景1.fdisk2.mda…

nvm更新node版本

1、nvm安装和管理多个 Node.js 版本&#xff1a;NVM 允许用户在计算机上同时安装多个不同版本的 Node.js。这使得开发人员可以轻松地在不同的项目中使用不同的 Node.js 版本&#xff0c;而无需手动安装或卸载。 2、nvm切换 Node.js 版本&#xff1a;通过 NVM&#xff0c;用户可…

好菜每回味道不同--建造者模式

1.1 炒菜没放盐 中餐&#xff0c;老板需要每次炒菜&#xff0c;每次炒出来的味道都有可能不同。麦当劳、肯德基这些不过百年的洋快餐却能在有千年饮食文化的中国发展的那么好呢&#xff1f;是因为你不管何时何地在哪里吃味道都一样&#xff0c;而鱼香肉丝在我们中餐却可以吃出上…

Langchain-Chatchat 从入门到精通(基于本地知识库的问答系统)(更新中)

目录 前言一、Langchain-Chatchat介绍1-1、Langchain-Chatchat介绍1-2、LangChainChatGLM 工作流1-3、文档角度的工作流 二、快速上手2-0、硬件要求2-1、环境配置2-2、模型下载2-3、初始化知识库和配置文件2-4、一键启动 三、配置文件详解&#xff08;config目录下&#xff09;…

浏览器输入域名执行全过程?

当你在浏览器中输入www.baidu.com并按下回车键时&#xff0c;会触发一系列复杂的过程才能在你的屏幕上显示出百度的首页。以下是这一过程的详细步骤&#xff1a; 1. 解析域名 首先&#xff0c;浏览器需要解析你输入的域名www.baidu.com。这个过程称为DNS查询。 浏览器缓存&a…