【JavaWeb后端学习笔记】登录校验(JWT令牌技术、Interceptor拦截器、Filter过滤器)

登录校验

  • 1、JWT令牌技术
    • 1.1 JWT令牌介绍
    • 1.2 Java代码生成与校验JWT令牌
  • 2、Filter过滤器
    • 2.1 Filter过滤器的简单实现
    • 2.2 配置拦截路径
    • 2.3 Filter接口中的三个方法:
    • 2.4 Filter过滤器登录校验
    • 2.5 过滤器链
  • 3、Interceptor拦截器
    • 3.1 拦截器(Interceptor)的简单实现
    • 3.2 配置拦截路径
    • 3.3 拦截器中的三个方法
    • 2.4 Interceptor拦截器登录校验

登录校验是系统开发中不可缺少的一环。

1、JWT令牌技术

1.1 JWT令牌介绍

JWT全称为 JSON Web Token(https://jwt.io/)。JWT定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
JWT令牌由三部分组成:

  1. 第一部分Header(头):记录令牌类型、签名算法等。例如:{“alg”:“HS256”,“type”:“JWT”}
  2. 第二部分Payload(有效载荷):携带一些自定义的信息,默认信息等。例如:{“id”:“1”,“username”:“Tom”}
  3. 第三部分Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

Header和Payload会通过Base64编码生成。Signature部分会通过Header指定的签名算法,以Header、Payload以及指定的秘钥作为签名算法输入计算得到。这三部分共同组成了JWT令牌。

1.2 Java代码生成与校验JWT令牌

Java代码生成与校验令牌需要引入JWT的相关依赖:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

生成JWT令牌需要准备四个数据:签名算法、秘钥、有效时间和载荷(自定义内容)
签名算法有很多种,可以在JWT官网查看。
下面通过一个简单的例子感受一下:
生成JWT令牌:

@Test
public void testJWT(){// 准备Map集合载荷Map<String, Object> claims = new HashMap<>();claims.put("id", 1);claims.put("name", "Tom");String jwt = Jwts.builder() // 使用Jwts中的builder()方法构造.signWith(SignatureAlgorithm.HS256, "wrj-web") // 指定签名算法和秘钥.setClaims(claims) // 加入载荷.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)) // 设置有效时间:当前时间 + 有效时长,单位为ms.compact();System.out.println(jwt);
}
// 运行输出:
// eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTczMzU0MTk2MX0.AgNXthmTMBJHKIeSaacBf-wThVNwsPi1F63sAqsuJkY

解析JWT令牌:

    @Test void testParseJWT(){Claims claims = Jwts.parser() // 使用Jwts中的parser()方法开始解析.setSigningKey("wrj-wrb") // 指定秘钥.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTczMzU0MTk2MX0.AgNXthmTMBJHKIeSaacBf-wThVNwsPi1F63sAqsuJkY") // 输入JWT令牌,此处直接输入上述代码生成的JWT令牌.getBody(); // 获取载荷System.out.println(claims);}
// 运行输出:
// {name=Tom, id=1, exp=1733541961}

通常会将JWT生成与解析的代码封装成JWT工具类来使用,JwtUtil工具类中只有两个成员方法,一个用于生成JWT令牌,一个用于解析JWT令牌:

public class JwtUtil {/*** 生成jwt* 使用Hs256算法, 私匙使用固定秘钥** @param secretKey jwt秘钥* @param ttlMillis jwt过期时间(毫秒)* @param claims    设置的信息* @return*/public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) {// 指定签名的时候使用的签名算法,也就是header那部分SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;// 生成JWT有效时间long expMillis = System.currentTimeMillis() + ttlMillis;Date exp = new Date(expMillis);// 设置jwt的bodyJwtBuilder builder = Jwts.builder()// 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的.setClaims(claims)// 设置签名使用的签名算法和签名使用的秘钥.signWith(signatureAlgorithm, secretKey.getBytes(StandardCharsets.UTF_8))// 设置过期时间.setExpiration(exp);return builder.compact();}/*** Token解密** @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个* @param token     加密后的token* @return*/public static Claims parseJWT(String secretKey, String token) {// 得到DefaultJwtParserClaims claims = Jwts.parser()// 设置签名的秘钥.setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))// 设置需要解析的jwt.parseClaimsJws(token).getBody();return claims;}
}

对于一般项目而言,JWT令牌需要的签名秘钥、有效时长以及前端传递过来的令牌名称是较为固定的,可以在配置到配置文件中,以便修改。
步骤如下:

  1. 在配置文件中自定义配置参数,代码如下:
web:jwt:# 设置jwt签名加密时使用的秘钥secret-key: itcast# 设置jwt过期时间 单位msttl: 7200000# 设置前端传递过来的令牌名称token-name: token
  1. 定义一个properties类用于接收配置信息,类名一般为JwtProperties,注意成员变量名与配置信息中设置的名称要对应。
@Component // 注册成Bean
@ConfigurationProperties(prefix = "web.jwt") // 关联到配置文件中web->jwt下的配置信息
@Data // Lombok注解,生成get/set等方法
public class JwtProperties {// 签名秘钥,与配置文件中secret-key对应private String secretKey;// jwt过期时间,与配置文件中ttl对应private long ttl;// 前端传递过来的令牌名称,与配置文件中token-name对应private String tokenName;
}

在需要使用这些信息时,只需要将JwtProperties 对象注入,然后通过get/set方法获取即可。

2、Filter过滤器

过滤器能够把对资源的请求拦截下来,从而实现一些特殊的功能,例如登录校验、敏感字符处理等。
在这里插入图片描述

2.1 Filter过滤器的简单实现

Filter过滤器使用分两步:

  1. 定义Filter:定义一个类,实现Filter接口,并重写其所有方法。Filter接口是javax.servlet.*包下的Filter接口。
  2. 配置Filter:Filter类上加@WebFilter注解,配置拦截资源路径。引导类(启动类)上加@ServletComponentScan开启Servlet组件支持。
@WebFilter(urlPatterns = "/*") // 通过WebFilter注解表示这是一个web过滤器组件,通过urlPatterns属性配置拦截路径
public class DemoFilter implements Filter {// 初始化方法、Web服务器启动,创建Filter时调用,只调用一次。通常在此方法中完成资源和环境的准备操作@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}// 每次拦截到请求时会调用@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("拦截请求...放行前逻辑");filterChain.doFilter(servletRequest, servletResponse);System.out.println("拦截请求...放行后逻辑");}// 销毁方法,Web服务器关闭时调用,只调用一次。通常完成资源的释放等操作@Overridepublic void destroy() {Filter.super.destroy();}
}

2.2 配置拦截路径

Filter过滤器的拦截路径通过 @WebFilter 注解中的 urlPatterns 属性设置,有三种方式:

拦截路径urlPatterns含义
拦截具体路径/login只有访问 /login 路径时,才会被拦截
目录拦截/emps/*访问 /emps 下的所有资源,都会被拦截
拦截所有/*访问所有资源,都会被拦截

2.3 Filter接口中的三个方法:

Filter接口中的三个方法有各自的执行时机和作用。

  • init():初始化方法、Web服务器启动,创建Filter时调用,只调用一次。通常在此方法中完成资源和环境的准备操作;
  • doFilter():每次拦截到请求时会调用。其中可包含放行前逻辑和放行后逻辑;
  • destroy():销毁方法,Web服务器关闭时调用,只调用一次。通常完成资源的释放等操作

在使用Filter过滤器时需要注意几点:

  1. 执行doFilter()方法时首先执行其中的放行前逻辑,然后放行。
  2. 过滤器放行,访问完对应路径的资源之后会回到过滤器。
  3. 回到过滤器之后还会执行放行后逻辑。

2.4 Filter过滤器登录校验

下面改造doFilter()方法,实现登录校验功能。
场景:用户进行登录操作不进行拦截,其他操作进行拦截。也就是不拦截"/login"路径,拦截其他所有路径。
拦截逻辑分为以下几步:
1.获取请求路径;
2.判断路径中是否包含"login",包含则直接放行,不包含则需拦截,进行登录校验;Filter放行是通过执行filterChain调用doFilter()方法
3.进行登录校验,首先获取JWT令牌;
4.判断JWT令牌是否存在,或是否为空。不存在或为空则校验失败,不放行,直接return结束。
5.解析JWT令牌,不成功则不放行;
6.解析JWT令牌成功则放行。

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;HttpServletResponse resp = (HttpServletResponse) servletResponse;// 1.获取请求的URLString url = req.getRequestURL().toString();// 2.判断login是否存在,存在则放行,不存在则拦截if(url.contains("login")) {filterChain.doFilter(servletRequest, servletResponse);return;}// 3.获取JWT令牌String jwt = req.getHeader("token");// 4.判断JWT是否存在if(!StringUtils.hasLength(jwt)) {Result error = Result.error("NOT_LOGIN");String s = JSONObject.toJSONString(error);resp.getWriter().write(s);return;}// 5.判断JWT是否能解析成功try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();Result error = Result.error("NOT_LOGIN");String s = JSONObject.toJSONString(error);resp.getWriter().write(s);return;}// 6.解析成功,放行filterChain.doFilter(servletRequest, servletResponse);}

这部分登录校验的代码是可以进行优化的。因为实际业务中是不会对 /login 登录请求进行拦截的。

2.5 过滤器链

一个Web应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。
由于存在多个过滤器,过滤器的执行顺序会按照过滤器类名(字符串)的自然顺序

3、Interceptor拦截器

拦截器是一种动态拦截方法调用的机制,类似与过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行。拦截器通常用来拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

3.1 拦截器(Interceptor)的简单实现

Interceptor拦截器的使用分两步:

  1. 定义拦截器:实现HandlerInterceptor接口,并重写其所有方法,在实现类上加上@Component注解,交给IOC容器管理;
@Component // 注册成Bean,交给IOC容器管理
public class DemoInterceptor implements HandlerInterceptor {// 目标资源方法执行前执行,返回true:放行,返回false:不放行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...");return true;}// 目标资源方法执行后执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}// 视图渲染完毕后执行,最后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
  1. 注册配置拦截器。创建一个配置类,实现WebMvcConfigurer接口。在配置类上加@Configuration注解,代表当前类是配置类。重写WebMvcConfigurer接口的addInterceptors方法,使用该方法的形参registry调用addInterceptor方法,将创建好的拦截器注册进去。因此需要先将拦截器注入。然后接着调用addPathPatterns()和excludePathPatterns()方法配置拦截哪些路径,不拦截哪些路径。
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate DemoInterceptor demoInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(demoInterceptor) // 注册拦截器.addPathPatterns("/**") // 配置拦截资源.excludePathPatterns("/login"); // 配置不拦截的资源               }
}

3.2 配置拦截路径

Interceptor拦截器的拦截路径是在配置类中进行配置的。可借鉴上述配置类的代码。
下面介绍Interceptor的拦截路径:

拦截路径含义举例
/*一级路径能匹配 /depts、/emps、/login,不能匹配 /depts/1
/**任意级路径能匹配 /depts、/depts/1、/depts/1/2
/depts/*/depts下的一级路径能匹配 /depts/1、不能匹配 /depts/1/2,/depts
/depts/**/depts下的任意级路径能匹配 /depts、/depts/1、/depts/1/2、不能匹配 /emps/1

3.3 拦截器中的三个方法

Interceptor接口中的三个方法有各自的执行时机和作用。

  • preHandle():目标资源方法执行前执行,返回true:放行,返回false:不放行;
  • postHandle():目标资源方法执行后执行;
  • afterCompletion():视图渲染完毕后执行,最后执行。

2.4 Interceptor拦截器登录校验

Interceptor拦截器进行登录校验与Filter过滤器实现登录校验的逻辑相同,只是部分实现细节不同。这里提供一个简单的实现。

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1. 获取请求路径String url = request.getRequestURL().toString();// 2. 判断请求路径是否包含 /loginif(url.contains("login")) {return true;}// 3. 从请求头获取token,一般把JWT令牌的key名设置为tokenString jwt = request.getHeader("token");// 4. 判断是否获取到JWT令牌if(!StringUtils.hasLength(jwt)) {Result error = Result.error("NOT_LOGIN");String s = JSONObject.toJSONString(error);response.getWriter().write(s);return false;}// 5. 解析JWT令牌try {JwtUtils.parseJWT(jwt);} catch (Exception e) {e.printStackTrace();Result error = Result.error("NOT_LOGIN");String s = JSONObject.toJSONString(error);response.getWriter().write(s);return false;}return true;}

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

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

相关文章

Linux系统下常用资源查看

一、查看CPU使用率 top 命令 top命令可以看到总体的系统运行状态和cpu的使用率 。 %us&#xff1a;表示用户空间程序的cpu使用率&#xff08;没有通过nice调度&#xff09; %sy&#xff1a;表示系统空间的cpu使用率&#xff0c;主要是内核程序。 %ni&#xff1a;表示用户空间且…

Flutter提示错误:无效的源发行版17

错误描述 Flutter从3.10.1 升级到3.19.4&#xff0c;在3.10.1的时候一切运行正常&#xff0c;但是当我将Flutter版本升级到3.19.4后&#xff0c;出现了下方的错误 FAILURE: Build failed with an exception.* What went wrong: Execution failed for task :device_info_plus:…

java+ssm+mysql学生信息管理系统

项目介绍&#xff1a; 使用javassmmysql开发的学生信息管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、教师、学生角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff08;可以新增管理员&#xff09;&#xff1b;专业管理&…

PCB设计规范

过孔设计 过孔盖油工艺&#xff08;也成为连塞带印&#xff09;&#xff1a;常规工艺、免费工艺&#xff0c;无特殊情况也建议使用此工艺。过孔大小建议直径在0.3mm-0.5mm之间。最省钱&#xff0c;效果最好。 非金属化槽孔 PCB制造商在加工非金属化槽孔时通常采用锣刀加工。最…

【C语言】42道大厂笔试题目(选择题)

本篇博客给大家带来的是一些大厂笔试题目&#xff0c;题目难度&#xff1a;简单&#xff0c;适合小白快速入手C语言部分的大厂笔试难度。 &#x1f41f;&#x1f41f;文章专栏&#xff1a;C语言 &#x1f680;&#x1f680;若有问题评论区下讨论&#xff0c;我会及时回答 ❤❤欢…

设置笔记本同时连接内外网

原理&#xff1a;通过笔记本和手机相连&#xff0c;实现双网卡功能能。笔记本连接内网wifi、同时手机端开启usb网络共享&#xff0c;笔记本就有了两个网&#xff0c;然配置那个访问外网&#xff0c;那个访问内网。 1.笔记本wifi连接内网wifi 2.手机端共享网络。 手机打开 -【…

JVM类加载三步解读: 双亲委派模型如何维护Java生态

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! &#x1f649;Java是面向对象编程&#xff0c;一切皆对象。这些对象是如何从一堆代码变成程序中的一部分&#xff1f;Java虚拟机&#xff08;JVM&#xff09;在这个过程中扮演了至关重要的角色。当你的代码通…

青海摇摇了3天,技术退步明显.......

最近快手上的青海摇招聘活动非常火热&#xff0c;我已经在思考是否备战张诗尧的秋招活动。开个玩笑正片开始&#xff1a; 先说一下自己的情况&#xff0c;大专生&#xff0c;20年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c…

SpringBean生命周期之PostConstruct、PreDestroy详解

在Spring框架中&#xff0c;Bean的生命周期是一个复杂的过程&#xff0c;涉及多个阶段&#xff0c;其中PostConstruct和PreDestroy注解在Bean的初始化和销毁阶段发挥着重要作用。以下是对这两个注解的深入理解&#xff1a; 一、PostConstruct注解 定义与来源 PostConstruct源自…

基于阿里云Ubuntu22.04 64位服务器Java及MySql环境配置命令记录

基于阿里云Ubuntu22.04 64位服务器Java及MySql环境配置命令记录 Java 23 离线环境配置MySql 环境配置MySQL常用命令 Java 23 离线环境配置 下载 Ubuntu环境下 Java 23 离线包 链接: java Downloads. 在Linux环境下创建一个安装目录 mkdir -p /usr/local/java将下载好的jdk压缩…

逆向分析:利用标志位进行爆破破解

信息收集 查程序编写信息 所用工具Detect It Easy Delphi编写&#xff0c;根据此信息选择DeDeDark进行反编译进一步收集可用信息 反编译程序进行信息收集 所用工具DeDeDark 载入要分析的主程序点击[开始处理]进行分析 注&#xff1a;主程序即软件主题程序(长见软件安装完毕…

【工具变量】上市公司企业研发不确定性数据(2013-2023年)

一、测算方式&#xff1a;参考顶刊《中国工业经济》孙薇&#xff08;2023&#xff09;老师的做法&#xff0c;本文从专利的申请与授权的视角出发&#xff0c;以企业当年申请的发明专利中最终未被授权的比例度量研发不确定性 &#xff08;uc&#xff09;。这是因为&#xff0c;相…

centos部署SkyWalking并在springcloud项目中用法举例

文章目录 场景SkyWalking介绍部署部署Storage [单机版Elasticsearch]部署SkyWalking OAP [下载地址](https://skywalking.apache.org/downloads/#SkyWalkingAPM)部署SkyWalking Java AgentspringCloud 使用举例 场景 SkyWalking是应用性能监控平台&#xff0c;可用于分布式系统…

[ACL 2024] ReFT: Reasoning with REinforced Fine-Tuning

Contents IntroductionMethodExperimentsReferences Introduction 作者提出 Reinforced Fine-Tuning (ReFT) 进行在线强化学习&#xff0c;帮助模型输出正确的推理步骤&#xff0c;总体感觉在线学习的思路和 STaR 非常相似&#xff0c;就是把 SFT 换成了 PPO… Method Warm-…

深度优先的艺术:探索二叉树的深搜算法精髓

文章目录 前言☀️一、计算布尔二叉树的值&#x1f319;解法⭐代码 ☀️二、求根节点到叶节点数字之和&#x1f319;解法⭐代码 ☀️三、二叉树剪枝&#x1f319;解法⭐代码 ☀️四、验证二叉搜索树&#x1f319;解法☁️步骤⭐代码 ☀️五、二叉搜索树中第k小的元素&#x1f3…

python学opencv|读取图像(五)读取灰度图像像素

【1】引言 前序学习了图像的基本读取&#xff0c;掌握了imread()、imshow()和imwrite()函数的基本功能和使用技巧&#xff0c;参考文章链接为&#xff1a; python学opencv|读取图像-CSDN博客 然后陆续掌握了彩色图像保存、图像放大和缩小以及对imshow()函数的大胆尝试技巧&a…

基于yolov8的SAR影像目标检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测、图像分类识别、目标追踪等项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的SAR影像目标检测系统&#xff0c;支持图像、视频和摄像实时检测【pytorch框架、python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的SAR影像目标…

ESP32开发 云调试

https://blog.csdn.net/weixin_43794311/article/details/128722001 VScode支持的仿真平台 https://docs.wokwi.com/zh-CN/vscode/getting-started 编译&#xff1a;Ctrl Alt B上传并重启模拟器&#xff1a;CtrlShifB Wokwi:Start Simulator调试&#xff1a;CtrlShifB Wokwi…

模版方法模式的理解和实践

在软件开发中&#xff0c;设计模式为我们提供了一套经过验证的解决方案&#xff0c;用于解决常见的设计问题。其中&#xff0c;模版方法模式&#xff08;Template Method Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个算法的框架&#xff0c;并允许子类在不改…

MySQL--》如何在SQL中巧妙运用函数与约束,优化数据处理与验证?

目录 函数使用 字符串函数 数值函数 日期函数 流程函数 约束 函数使用 函数是指一段可以直接被另一段程序调用的程序或代码&#xff0c;在mysql当中有许多常见的内置函数&#xff0c;接下来开始对这些内置函数及其作用进行简单的讲解和使用&#xff1a; 字符串函数 my…