springbot,JWT令牌的使用。实现http请求拦截校验。

news/2024/12/21 22:50:27/

 

JWT 由三部分组成,用点(.)分隔 Header(头部) Payload(负载)Signature(签名)

 一、原理

Jwt原理其实很简单,在后端首先要有个拦截器,他会拦截所有http请求,意思就是所有访问都被拦截掉,当然这是不合理的。所以首先我们要手动放行登陆页面,也就是登录请求不拦截可以访问,然后自此以后的所有请求都会被拦截。如何不让他拦截呢?这时候就要设置一些规则来放行请求,那么这个规则就是Jwt令牌的用处。他会生成一个token在前后端传来传去,怎么传呢?前端的http请求都有一个header,token就会被携带在里面,后端解析http请求,拿到token来验证。如果通过则放行,不通过就拦截。注意(token在实体类中有字段,但是数据库中不必有专门的列来保存token)

  @TableField(exist = false)private String token;

二、第一次请求生成token,不验证token

1.首先,当用户成功登陆时,会请求/login

 @PostMapping("/login")public Result login(@RequestBody User user) {if(StrUtil.isBlank(user.getUsername()) || StrUtil.isBlank(user.getPassword())) {return Result.error("帐号或密码不能为空");}user  = userService.loginUser(user);return Result.success(user);}

2.访问user的服务层的loginUSer,先通过user参数,查询对应的user给dbuser,判断是否存在,和user参数的密码和查到的密码是否相同。都满足则创建token,把token通过set方法给dbuser,返回给前端

 @Overridepublic User loginUser(User user) {User dbuser =  userMapper.selectByUsername(user.getUsername());if(dbuser == null){throw new ServiceException("用户名或密码错误");}if(!user.getPassword().equals(dbuser.getPassword())){throw new ServiceException("用户名或密码错误");}String token = TokenUtils.createToken(dbuser.getId().toString(), dbuser.getPassword());dbuser.setToken(token);return dbuser;}

这里面用到了TokenUtils的createToken方法,就是生成token的地方

@Component // 标记此类为Spring组件,使其可以被Spring管理
public class TokenUtils {// 声明一个静态的UserMapper,用于在静态方法中访问用户数据private static UserMapper staticUserMapper;// 注入UserMapper实例@ResourceUserMapper userMapper;// 在类实例化后,设置静态的UserMapper@PostConstruct // 标记此方法在构造函数后自动执行public void setUserService() {staticUserMapper = userMapper; // 将实例UserMapper赋值给静态变量}/*** 生成token** @param userId 用户ID* @param sign   用于签名的密钥* @return 生成的token字符串*/public static String createToken(String userId, String sign) {// 创建JWT并设置载荷return JWT.create().withAudience(userId) // 将用户ID存储在token的载荷中.withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 设置token有效期为2小时.sign(Algorithm.HMAC256(sign)); // 使用指定的密钥签名token}}

三、随后的请求都要验证token

上面我们已经说到第一次请求,也就是登录时会生成token,返回给前端。前端会保存在浏览器中,以后每次header里面都会携带这个token,那么现在就开始第二次请求。

1.验证token过程

因为拦截器的作用,发过来的http请求会被拦截,以验证规则。

当前端请求发送到后端会首先进到这里验证token,而不是直接访问@GetMapping("*请求的接口*")

首先,会从请求头拿token,如果没有则拦截,否则 验证token是否为空,如果为空拦截,

不为空后,解析token中user的id,然后查询数据库是否有这个user,否则拦截,当查到后,

使用用户密码生成一个验证器(为什么是密码呢?因为上面我们生成token时就是用密码作为密钥),与传过来的token进行验证,如果通过则,验证成功,不拦截请求,访问@GetMapping("*请求的接口*")

/*** 功能:JWT 拦截器,用于对请求进行身份验证* 作者:lhp* 日期:2024/9/26 23:01*/
public class JwtInterceptor implements HandlerInterceptor {@Resourceprivate UserMapper userMapper; // 自动注入 UserMapper,用于数据库操作@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 从请求头中获取 tokenString token = request.getHeader("token");// 如果请求头中没有 token,则尝试从请求参数中获取if (StrUtil.isBlank(token)) {token = request.getParameter("token");}// 执行认证,首先检查 token 是否为空if (StrUtil.isBlank(token)) {// 如果 token 为空,抛出未授权异常throw new ServiceException("401", "请登录");}// 获取 token 中的用户 IDString userId;try {userId = JWT.decode(token).getAudience().get(0); // 解码 token,获取用户 ID} catch (JWTDecodeException j) {// 解码失败,抛出未授权异常throw new ServiceException("401", "请登录");}// 根据 token 中的 userId 查询数据库,获取用户信息User user = userMapper.selectById(Integer.valueOf(userId));if (user == null) {// 如果用户不存在,抛出未授权异常throw new ServiceException("401", "请登录");}// 使用用户密码生成 JWTVerifier,用于验证 tokenJWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();try {// 验证 token 的有效性jwtVerifier.verify(token);} catch (JWTVerificationException e) {// 验证失败,抛出未授权异常throw new ServiceException("401", "请登录");}// 所有验证通过,返回 true,表示请求可以继续return true;}
}

 至此就是Jwt的整个流程。以下是拦截器的代码,这个配置类的主要功能是设置一个 JWT 拦截器,用于拦截所有的 HTTP 请求,以便于进行身份验证,但对 /login 请求路径不进行拦截

/*** 功能:拦截器配置类,用于配置和注册自定义的拦截器* 作者:lhp* 日期:2024/9/26 23:15*/
@Configuration // 标记该类为配置类,Spring 会在运行时自动识别并加载该类的 Bean 定义
public class InterceptorConfig extends WebMvcConfigurationSupport {/*** 重写 addInterceptors 方法,用于添加自定义拦截器* * @param registry 拦截器注册中心,用于注册自定义拦截器*/@Overrideprotected void addInterceptors(InterceptorRegistry registry) {// 注册 JwtInterceptor 拦截器registry.addInterceptor(jwtInterceptor()).addPathPatterns("/**") // 拦截所有请求路径.excludePathPatterns("/login"); // 排除登录路径,不拦截登录请求// 调用父类的 addInterceptors 方法,确保其他配置能够正常工作super.addInterceptors(registry);}/*** 定义 JwtInterceptor Bean,Spring 会自动管理该 Bean 的生命周期* * @return JwtInterceptor 实例*/@Beanpublic JwtInterceptor jwtInterceptor() {return new JwtInterceptor(); // 创建并返回 JwtInterceptor 的新实例}
}

 

 

 


http://www.ppmy.cn/news/1534545.html

相关文章

方舟开发框架(ArkUI)可运行 OpenHarmony、HarmonyOS、Android、iOS等操作系统

ArkUI 是华为开发的一套声明式 UI 开发框架,用于构建分布式应用界面。ArkUI-X 是对 ArkUI 框架的扩展,支持开发者使用一套代码构建支持多平台(包括 OpenHarmony、HarmonyOS、Android、iOS)的应用。 一、方舟开发框架的ArkUI-X Ark…

quiz: python网络爬虫之规则1

下面答错了: B c 8A, 9A

10.3 Linux_并发_创建守护进程

守护进程创建方法 守护进程是什么: 守护进程又叫精灵进程,是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。它是一个在后台运行的孤儿进程,这使得守护进程不受终端的信息影响&…

C# 字符串(String)的应用说明一

一.字符串(String)的应用说明: 在 C# 中,更常见的做法是使用 string 关键字来声明一个字符串变量,也可以使用字符数组来表示字符串。string 关键字是 System.String 类的别名。 二.创建 String 对象的方法说明&#x…

【学习笔记】手写一个简单的 Spring IOC

目录 一、什么是 Spring IOC? 二、IOC 的作用 1. IOC 怎么知道要创建哪些对象呢? 2. 创建出来的对象放在哪儿? 3. 创建出来的对象如果有属性,如何给属性赋值? 三、实现步骤 1. 创建自定义注解 2. 创建 IOC 容器…

影响 Linux、Unix 系统的 CUPS 漏洞可导致 RCE

在经过大量炒作和第三方过早泄露信息之后,安全研究员 Simone Margaritelli 公布了有关通用 UNIX 打印系统 (CUPS) 中的四个零日漏洞的详细信息。 这些漏洞可被远程、未经身份验证的攻击者滥用,在易受攻击的 Linux 和类 Unix 系统上实现代码执行。 CUPS…

力扣题解 1928

题目描述(困难) 规定时间内到达终点的最小费用 一个国家有 n 个城市,城市编号为 0 到 n - 1 ,题目保证 所有城市 都由双向道路 连接在一起 。道路由二维整数数组 edges 表示,其中 edges[i] [xi, yi, timei] 表示城市…

Redis: 集群测试和集群原理

集群测试 1 ) SET/GET 命令 测试 set 和 get 因为其他命令也基本相似,我们在 101 节点上尝试连接 103 $ /usr/local/redis/bin/redis-cli -c -a 123456 -h 192.168.10.103 -p 6376我们在插入或读取一个 key的时候,会对这个key做一个hash运算&#xff0c…