SpringBoot配置JWT拦截器

目录

1.背景介绍

2.前提工作

3.具体代码

(1)相关依赖

(2)相关配置文件

(3)JwtUtils类

(4)准备好登录逻辑代码(Dao、Service、Controller)

(5)拦截器JwtInterceptor类

(6)注册拦截器到配置类

4. 测试


1.背景介绍

        JWT在之前文章提到过,JWT(JSON Web Token)是一种用于身份验证和授权的开放标准(RFC 7519),它允许在网络中安全地传输声明(claims)作为 JSON 对象。JWT 可以通过数字签名或加密来验证数据的完整性和真实性,从而保证数据在传输过程中不被篡改。

        工作流程

  1. 用户通过用户名和密码等方式进行身份验证。
  2. 服务器验证用户身份,并生成一个 JWT。
  3. 服务器将 JWT 发送给客户端
  4. 客户端将 JWT 存储起来,通常是在本地存储或者内存中。
  5. 客户端将 JWT 添加到每个后续的 HTTP 请求的 Authorization 头部中。
  6. 服务器收到请求后,解析 JWT 并验证签名。
  7. 如果验证通过,则处理请求;如果验证失败,则拒绝请求。

2.前提工作

        1.Redis,用于将生成的token存入其中

        2.用户登录Controller

        3.Jwtutils、相关依赖

        4.拦截器JwtInterceptor

        5.配置类WebMvcConfig,用于注册拦截器

3.具体代码

(1)相关依赖
        <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.2</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
(2)相关配置文件
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/login?useSSL=false&serverTimezone=UTCusername: #自己的数据库用户名password: #自己的数据库密码redis:host: localhostport: 6379mybatis:mapper-locations: classpath:mapper/*.xmljwt:secret: T7e3t3AhK9kS2DdF6gZr4e7hWmYq3t5vT7e3t3AhK9kS2DdF6gZr4e7hWmYq3t5vT7e3t3AhK9kS2DdF6gZr4e7hWmYq3t5vT7e3t3AhK9kS2DdF6gZr4e7hWmYq3t5vexpiration: 864000
(3)JwtUtils类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.concurrent.TimeUnit;@Component
public class JwtUtils {@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private  long expiration;/*** 生成token* @param username* @return*/public  String generateToken(String username) {String token = Jwts.builder().setSubject(username).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expiration)).signWith(SignatureAlgorithm.HS512, secret).compact();// 将 Token 存储到 Redis 中redisTemplate.opsForValue().set(username, token, expiration, TimeUnit.MILLISECONDS);return token;}/*** 验证token* @param token* @return*/public boolean validateToken(String token) {// 从 Token 中获取用户名String username = getUsernameFromToken(token);// 从 Redis 中获取存储的 TokenString storedToken = redisTemplate.opsForValue().get(username);// 判断 Redis 中存储的 Token 是否与传入的 Token 相同return storedToken != null && storedToken.equals(token);}/*** 删除token* @param username*/public void removeToken(String username) {// 从 Redis 中删除 TokenredisTemplate.delete(username);}/*** 根据token获取用户信息* @param token* @return*/public String getUsernameFromToken(String token) {Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);Claims claims = claimsJws.getBody();return claims.getSubject();}/*** 判断token是否存在* @param username* @return*/public String getTokenIfExists(String username) {// Check if a valid token exists in Redis for the given usernameString storedToken = redisTemplate.opsForValue().get(username);// Validate the stored tokenif (storedToken != null && validateToken(storedToken)) {return storedToken;} else {return null;}}}
(4)准备好登录逻辑代码(Dao、Service、Controller)
import com.zhan.zhan215.Entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface UserMapper{User getUserByUsernameAndPassword(@Param("username")String username,@Param("password")String password);}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhan.zhan215.Dao.UserMapper"><select id="getUserByUsernameAndPassword" parameterType="com.zhan.zhan215.Entity.User" resultType="com.zhan.zhan215.Entity.User">select *from userWHERE username = #{username} AND password = #{password}</select></mapper>
@RestController
@RequestMapping("/user")
@Api(tags = "User API", description = "Operations for managing users")
public class UserController {@Resourceprivate UserService userService;@Resourceprivate JwtUtils jwtUtils;@PostMapping("/login")@ApiOperation(value = "登录控制器")public ResponseBean login(@RequestParam(value = "username") String username, @RequestParam(value = "password") String password) {User user1 = userService.getUserByUsernameAndPassword(username, password);System.out.println(user1);if(user1!=null) {// 检查用户是否有tokenString existingToken = jwtUtils.getTokenIfExists(username);if(existingToken!=null){return ResponseBean.success("已存在token,无需重复登录",existingToken);}else{// 生成tokenString token = jwtUtils.generateToken(username);System.out.println(token);return ResponseBean.success("登录成功", token);// 将token返回给前端}}return ResponseBean.error("用户名或密码错误");}@GetMapping("/get")public ResponseBean getAll(@RequestHeader("Authorization") String token){if(jwtUtils.validateToken(token)){return ResponseBean.success(userMapper.getAll());}else{return ResponseBean.error("token无效");}// 倘若不写拦截器 则每个请求方法都要像getAll这样去做判断,非常麻烦}@GetMapping("/getAllByPage")public ResponseBean getAllByPage(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "2") Integer size) {return ResponseBean.success(userService.getAllByPage(page, size));}
}
(5)拦截器JwtInterceptor类
import com.zhan.zhan215.Utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class JwtInterceptor implements HandlerInterceptor {@Autowiredprivate JwtUtils jwtUtils;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 从请求头中获取 tokenString token = request.getHeader("Authorization");// 验证 tokenif (token != null && jwtUtils.validateToken(token)) {return true; // 验证通过,继续处理请求} else {// 设置响应状态码为 401response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);// 设置响应内容为 JSON 格式的错误信息String errorMessage = "{\"error\": \"token无效\"}";response.setContentType("application/json");response.setCharacterEncoding("UTF-8");response.getWriter().write(errorMessage);return false; // 验证失败,不继续处理请求}}}
(6)注册拦截器到配置类
import com.zhan.zhan215.Interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebMvcConfig  implements WebMvcConfigurer {@Autowiredprivate JwtInterceptor jwtInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor).addPathPatterns("/user/getAllByPage")// 配置拦截路径,这里假设所有 API 都需要验证 token.excludePathPatterns("/user/search");// 这是可以排除的路径,// 比如登录接口,登录接口不需要 token 验证// 如果有多个拦截器,可以这样继续添加// registry.addInterceptor(jwtInterceptor).addPathPatterns("/user/login");// registry.addInterceptor(jwtInterceptor).addPathPatterns("/user/update");// registry.addInterceptor(jwtInterceptor).addPathPatterns("/user/delete");// registry.addInterceptor(jwtInterceptor).addPathPatterns("/user/getById");}}

4. 测试

先进行登录:

在后端控制台查看token

未携带请求头:

携带请求头后:

说明拦截器生效

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

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

相关文章

解决方案Please use Oracle(R) Java(TM) 11, OpenJDK(TM) 11 to run Neo4j.

文章目录 一、现象二、解决方案 一、现象 当安装好JDK跟neo4j&#xff0c;用neo4j.bat console来启动neo4却报错&#xff1a; 部分报错信息&#xff1a; Starting Neo4j. WARNING! You are using an unsupported Java runtime. Please use Oracle Java™ 11, OpenJDK™ 11 t…

大白话扩散模型(无公式版)

背景 传统的图像生成模型有GAN&#xff0c;VAE等&#xff0c;但是存在模式坍缩&#xff0c;即生成图片缺乏多样性&#xff0c;这是因为模型本身结构导致的。而扩散模型拥有训练稳定&#xff0c;保持图像多样性等特点&#xff0c;逐渐成为现在AIGC领域的主流。 扩散模型 正如…

Google ScreenAI代表了一款先进的视觉语言模型,专为用户界面(UI)和视觉情境下的语言理解而设计

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

政安晨:【深度学习部署】—— TensorFlow Extended(TFX)介绍

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎机器学习 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 前言 TensorFlow Extended&#xff08;TFX&a…

深入了解Redis的过期策略和内存淘汰机制

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起进步&am…

mysql基础2多表查询

多表查询 多表关系: 一对多 案例: 部门 与 员工的关系 关系: 一个部门对应多个员工&#xff0c;一个员工对应一个部门 实现: 在多的一方建立外键&#xff0c;指向一的一方的主键 多对多 案例: 学生 与 课程的关系 关系: 一个学生可以选修多门课程&#xff0c;一门课程也可以…

RuleApp资源社区,知识付费社区,可对接typecho的小程序APP

强大的文章/社区/自媒体客户端&#xff0c;支持打包为安卓&#xff0c;苹果&#xff0c;小程序。包括文章模块&#xff0c;用户模块&#xff0c;支付模块&#xff0c;聊天模块&#xff0c;商城模块等基础功能&#xff0c;包含VIP会员&#xff0c;付费阅读等收费体系&#xff0c…

AttributeError: ‘_MSDataLoaderIter‘ object has no attribute ‘_put_indices‘

问题描述 复现代码过程中遇到错误&#xff1a;AttributeError: _MSDataLoaderIter object has no attribute _put_indices 解决方案 出错的原因是代码中使用了不存在的属性"_put_indices"。这个错误可能与你使用的版本不兼容有关。在pytorch1.x版本中&#xff0c;&q…

Django Ajax

【一】Json 【1】介绍 JSON&#xff08;javascript object otaition&#xff09;是一种轻量级的数据交换格式JSON使用了Javascript的一部分语法来定义其数据格式&#xff0c;但Json是独立于语言的Json采用完全独立于语言的文本格式&#xff0c;使得Json成为理想的数据交互语言…

react native 键盘事件

在做修改密码功能是发现他的键盘第一次调起之后然后收起键盘焦点不会消失而且键盘也不会再调起来了 我门线引入需要的组件 import { StyleSheet, View, TextInput, Keyboard, TouchableWithoutFeedback, } from react-native; import React, {useEffect, useState, useRef} fr…

[Halcon学习笔记]在Qt上实现Halcon窗口的字体设置颜色设置等功能

1、 Halcon字体大小设置在Qt上的实现 在之前介绍过Halcon窗口显示文字字体的尺寸和样式&#xff0c;具体详细介绍可回看 &#xff08;一&#xff09;Halcon窗口界面上显示文字的字体尺寸、样式修改 当时介绍的设定方法 //Win下QString Font_win "-Arial-10-*-1-*-*-1-&q…

MySQL学习笔记------SQL(2)

ziduanSQL DML 全称为&#xff1a;Data Manipulation Language&#xff0c;用来对数据库中表的数据记录进行增删改操作 插入数据 添加数据&#xff08;INSERT&#xff09; 给指定字段添加数据&#xff1a;INSERT INTO 表名(字段名1&#xff0c;字段名2&#xff0c;......…

【PyQt】19-数据操作

数据表 前言一、显示二维表数据&#xff08;QTableView控件&#xff09;扩展知识---MVC模式1.1 代码1.2 运行结果 二、显示列数据&#xff08;QListView控件&#xff09;2.1 代码2.2 运行结果2.3 扩展---列表控件&#xff08;QListWidget&#xff09;运行结果 总结 前言 一、显…

STM32使用滴答定时器实现delayms

在STM32上使用SysTick实现jiffies&#xff08;时间戳&#xff09;并且实现delay_ms 代码实现&#xff1a; volatile uint32_t jiffies 0; // 用于记录系统运行的jiffies数 void SysTick_Handler(void) {/* 每次SysTick中断&#xff0c;jiffies增加 */jiffies; }uint32_t tick…

unity无法使用道路生成插件Road Architect(ctrl和shift无法标点)

切换一下布局就行了。 附&#xff1a;Road Architect教学地址

游戏引擎中的地形系统

一、地形的几何 1.1 高度图 记录不同定点的高度&#xff0c;对每个网格/顶点应用高度、材质等信息&#xff0c;我们每个顶点可以根据高度改变位移 但是这种方法是不适用于开放世界的。很难直接画出几百万公里的场景 1.2 自适应网格细分 当fov越来越窄的时候&#xff0c;网格…

JavaEE企业级分布式高级架构师课程

教程介绍 本课程主要面向1-5年及以上工作经验的Java工程师&#xff0c;大纲由IT界知名大牛 — 廖雪峰老师亲自打造&#xff0c;由来自一线大型互联网公司架构师、技术总监授课&#xff0c;内容涵盖深入spring5设计模式/高级web MVC开发/高级数据库设计与开发/高级响应式web开发…

深度学习pytorch——GPU加速(持续更新)

使用 .to(device)&#xff0c;以前使用 .cuda() &#xff0c;但是现在基本不使用了。 代码示例&#xff1a; 查看电脑GPU运行情况&#xff1a; 使用Ctrl Shift ESC快捷键&#xff1a;

目标检测上的diffusion

1 Title DiffusionDet: Diffusion Model for Object Detection&#xff08;Shoufa Chen,Peize Sun,Yibing Song,Ping Luo&#xff09;【ICCV 2023】 2 Conclusion This study proposes DiffusionDet, a new framework that formulates object detection as a denoisin…

吴恩达2022机器学习专项课程(一) 3.3 成本函数的公式

问题预览 模型的参数&#xff08;w和b&#xff09;有什么作用&#xff1f;不同的w和b对线性回归模型有什么影响&#xff1f;训练集里的y和线性回归模型预测的y&#xff08;y帽&#xff09;的区别是什么&#xff1f;成本函数的作用是什么&#xff1f;成本函数的公式是什么&…