当前位置: 首页 > news >正文

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

 

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.lryc.cn/news/451743.html

相关文章:

  • 【SQL】DDL语句
  • 【分页】Spring Boot 列表分页 + javaScript前台展示
  • 「安装」 Windows下安装CUDA和Pytorch
  • c语言基础作业
  • uniapp view增加删除线
  • [Day 83] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
  • Java ReentrantLock
  • 【Linux系统编程】第二十六弹---彻底掌握文件I/O:C/C++文件接口与Linux系统调用实践
  • 数据分析-29-基于pandas的窗口操作和对JSON格式数据的处理
  • Ubuntu-WSL2一键设置代理操作
  • ubuntu命令行连接wifi
  • 日常工作第10天:
  • CNN+Transformer解说
  • jmeter中token测试
  • 基于解压缩模块的JPEG同步重压缩检测论文学习
  • 音视频入门基础:FLV专题(7)——Tag header简介
  • 【Linux 报错】“make: ‘xxxx‘ is up to date.” 解决办法
  • 【FPGA开发】Xilinx FPGA差分输入时钟的使用方法
  • 面试扩展知识点
  • 【经验分享】MyCAT 中间件
  • Kotlin:1.8.0 的新特性
  • 深度学习之开发环境(CUDA、Conda、Pytorch)准备(4)
  • 10月2日笔记(内网资源探测篇)
  • SpringCloud-基于Docker和Docker-Compose的项目部署
  • Linux下的基本指令/命令(一)
  • 从零开始Ubuntu24.04上Docker构建自动化部署(四)Docker安装gitlab
  • No module named ‘_ssl‘
  • Linux —— Socket编程(三)
  • 5G N2 N3 N6 NB口
  • 【数据结构】堆(Heap)详解