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

news2024/10/4 16:24:09

 

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,返回给前端

 @Override
    public 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实例
    @Resource
    UserMapper 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 {

    @Resource
    private UserMapper userMapper; // 自动注入 UserMapper,用于数据库操作

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 从请求头中获取 token
        String token = request.getHeader("token");
        // 如果请求头中没有 token,则尝试从请求参数中获取
        if (StrUtil.isBlank(token)) {
            token = request.getParameter("token");
        }

       

        // 执行认证,首先检查 token 是否为空
        if (StrUtil.isBlank(token)) {
            // 如果 token 为空,抛出未授权异常
            throw new ServiceException("401", "请登录");
        }

        // 获取 token 中的用户 ID
        String 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,用于验证 token
        JWTVerifier 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 拦截器注册中心,用于注册自定义拦截器
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 注册 JwtInterceptor 拦截器
        registry.addInterceptor(jwtInterceptor())
                .addPathPatterns("/**") // 拦截所有请求路径
                .excludePathPatterns("/login"); // 排除登录路径,不拦截登录请求
        
        // 调用父类的 addInterceptors 方法,确保其他配置能够正常工作
        super.addInterceptors(registry);
    }

    /**
     * 定义 JwtInterceptor Bean,Spring 会自动管理该 Bean 的生命周期
     * 
     * @return JwtInterceptor 实例
     */
    @Bean
    public JwtInterceptor jwtInterceptor() {
        return new JwtInterceptor(); // 创建并返回 JwtInterceptor 的新实例
    }
}

 

 

 

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

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

相关文章

Elasticsearch学习记录

阅读前须知 本文通过安装elasticsearch-7.17.0为基础,使用 kibana-7.17.0 对 elasticsearch 进行操作,本文中 es 是对 elasticsearch 的简写。 下载地址:elasticsearch_免费高速下载|百度网盘-分享无限制 (baidu.com) 1 初识Elasticsearch …

vue3 + ts + cesium:绘制、更新圆 ellipse

本文主要实现基础的绘制圆形,并且可以通过拖动圆心更新圆的位置,拖动圆上的边缘点改变圆的半径。 实现效果: (1)单击鼠标左键开始绘制,确定圆的圆心,移动鼠标,改变圆的半径&#xff…

CodeFormer模型构建指南

一、介绍 在 NeurIPS 2022 上,南洋理工大学-商汤科技联合研究中心 S-Lab 提出了一种基于 VQGANTransformer的人脸复原模型 CodeFormer。基于CodeFormer模型实现面部复原、增强旧照片/修复AI艺术、面部颜色增强和修复、面部修复四个功能。 二、特点 CodeFormer 是…

常用组件详解(九):学习率更新策略

文章目录 1.StepLR2.MultiStepLR3.ExponentialLR4.LinearLR5.PloyLR 适合的学习率能够更好地训练模型,为此衍生出多种学习率调整策略。一般来说,在训练初期希望学习率大一些,使得网络收敛迅速,在训练后期希望学习率小一些&#xf…

jmeter学习(4)提取器

同线程组https://blog.csdn.net/vikeyyyy/article/details/80437530 不同线程组 在JMeter中,正则表达式提取的参数可以跨线程组使用。 通过使用Beanshell后置处理器和属性设置函数,可以将提取的参数设置为全局变量,从而在多个线程组之间共享…

Spring Boot新闻推荐系统设计与实现

3系统分析 3.1可行性分析 通过对本新闻推荐系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本新闻推荐系统采用JAVA作为开发语言,Spring Boot框…

Go语言实现长连接并发框架 - 开篇

文章目录 前言初步设计思路初步架构图项目地址最后 前言 你好,我是醉墨居士,国庆假期闲来无事,准备使用Go语言开发一个轻量级的长连接并发框架,希望能够帮助大家掌握这类框架的心脏与内核,也希望能给大伙带来灵感与启…

【微服务】负载均衡 - LoadBalance(day4)

下述所有代码都是在订单服务中修改的,商品服务并不需要修改,只需要启动多个实例即可。 引入 在介绍Eureka组件的最后,留下了一个问题就是,无论启动多少个实例,只能调用第一个。原因是因为服务调用时获取的是一个实例…

C/C++/EasyX——入门图形编程(3)

【说明】上一篇讲了基础图形的绘制,那么这一篇就来讲一下如何在窗口上绘制文字吧,友友们一起学习吧。(>y<)(^v^) 一:文字…

jQuery——对象的过滤

在 jQuery 对象中的元素对象数组中过滤出一部分元素来 ① first() ② last() ③ eq(index / -index) ④ filter(selector):对当前元素提要求 ⑤ not(sel…

电脑IP地址怎么换成二进制:详解转换过程与应用

在电脑网络的世界里,IP地址是每台设备独一无二的身份标识。而我们日常所见的IP地址,大多是以点分十进制的形式呈现。然而,在电脑内部,IP地址实际上是以二进制的形式进行存储和处理的。那么,电脑IP地址怎么换成二进制呢…

pygame入门(千字详细版)

千字赘述,万字总结,就为博客点一赞吧! 1.安装pygame pip install pygame 安装完成后在python中输入检验有没有问题,回车键应该不会报错。 >>>import pygame >>>2.pygame模块预览 3.项目实战 3.1.0 hello w…

一键开启高清录屏:盘点Windows最火四款录屏工具

嘿,朋友们,今天咱们来聊聊那些让我在电脑前忙活得热火朝天的录屏神器究竟怎么样。作为一个经常需要录制教程、分享游戏精彩瞬间的普通用户,我可是对这几款软件有着满满的体验心得,现在就给你们一一道来。 一、福昕录屏大师 网址…

编码与解码

文章目录 编码与解码一、字节 & 字符二、编码 & 解码三、字符集 & 字符编码四、ASCII五、ISO-8859-1六、GB七、Unicode1、概述2、发展3、UTF-8 编码4、UTF-16 编码 八、Base64 编码1、概述2、原理3、代码示例 九、十六进制编码 编码与解码 一、字节 & 字符 字…

kali下编译AOSP报错(libncurses.so.5: cannot open shared object file)

编译报错信息:libncurses.so.5: cannot open shared object file: No such file or directory /bin/bash -c "PWD/proc/self/cwd prebuilts/clang/host/linux-x86/clang-3289846/bin/clang -Ifr ameworks/rs/script_api/include -Iexternal/clang/lib/Headers …

【AI知识点】小世界网络(Small-World Networks)

小世界网络(Small-World Networks) 是一种具有独特拓扑结构的网络模型,广泛应用于研究社交网络、神经网络、互联网以及其他复杂系统中的节点间连接方式。小世界网络的特点是节点之间的平均路径长度较短,并且大多数节点的局部连接较…

世邦通信股份有限公司IP网络对讲广播系统RCE

漏洞描述 SPON世邦IP网络广播系统采用的IPAudio™技术, 将音频信号以数据包形式在局域网和广域网上进行传送,是一套纯数字传输的双向音频扩声系统。传统广播系统存在的音质不佳,传输距离有限,缺乏互动等问题。该系统设备使用简便&#xff0c…

知识图谱入门——7:阶段案例:使用 Protégé、Jupyter Notebook 中的 spaCy 和 Neo4j Desktop 搭建知识图谱

在 Windows 环境中结合使用 Protg、Jupyter Notebook 中的 spaCy 和 Neo4j Desktop,可以高效地实现从自然语言处理(NLP)到知识图谱构建的全过程。本案例将详细论述环境配置、步骤实现以及一些扩展和不足之处。 文章目录 1. 环境准备1.1 Neo4j…

webGL入门(六)图形旋转

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</…

PIDM—— 物理正则化扩散模型

概述 论文地址&#xff1a;https://arxiv.org/pdf/2403.14404 源码地址&#xff1a;https://github.com/jhbastek/physicsinformeddiffusionmodels 扩散模型在逼近非常复杂的数据分布方面具有极高的性能和多功能性&#xff0c;近年来在自然科学领域的应用迅速扩展。鉴于其在科…