如何在Spring Boot项目中集成JWT实现安全认证?
在Spring Boot项目中集成JWT实现安全认证是常见的需求。本文将详细介绍如何在Spring Boot项目中集成JWT,并通过一个完整的示例演示如何实现安全认证。
一、环境准备
首先,确保你的Spring Boot项目已经创建。然后,添加以下依赖到pom.xml文件中:
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- JJWT for JWT handling --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.5</version><scope>runtime</scope></dependency><!-- Lombok for boilerplate code reduction --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency>
</dependencies>
二、JWT工具类
接下来,我们创建一个JWT工具类,用于生成和解析JWT令牌。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;@Component
public class JwtUtil {private static final Key SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);private static final long EXPIRATION_TIME = 864_000_000; // 10 dayspublic String generateToken(UserDetails userDetails) {Map<String, Object> claims = new HashMap<>();return createToken(claims, userDetails.getUsername());}private String createToken(Map<String, Object> claims, String subject) {return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).signWith(SECRET_KEY).compact();}public Boolean validateToken(String token, UserDetails userDetails) {final String username = extractUsername(token);return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));}public String extractUsername(String token) {return extractClaim(token, Claims::getSubject);}public Date extractExpiration(String token) {return extractClaim(token, Claims::getExpiration);}private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {final Claims claims = extractAllClaims(token);return claimsResolver.apply(claims);}private Claims extractAllClaims(String token) {return Jwts.parserBuilder().setSigningKey(SECRET_KEY).build().parseClaimsJws(token).getBody();}private Boolean isTokenExpired(String token) {return extractExpiration(token).before(new Date());}
}
三、自定义UserDetailsService
为了加载用户信息,我们需要实现UserDetailsService接口。
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;@Service
public class CustomUserDetailsService implements UserDetailsService {@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// In a real application, you would load the user from a databaseif ("admin".equals(username)) {return new User("admin", "password", new ArrayList<>());} else {throw new UsernameNotFoundException("User not found with username: " + username);}}
}
四、配置Spring Security
接下来,配置Spring Security以使用JWT进行认证。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate CustomUserDetailsService customUserDetailsService;@Autowiredprivate JwtUtil jwtUtil;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserDetailsService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/authenticate").permitAll().anyRequest().authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);http.addFilterBefore(new JwtRequestFilter(jwtUtil, customUserDetailsService), UsernamePasswordAuthenticationFilter.class);}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
}
五、JWT请求过滤器
创建一个过滤器来拦截请求并验证JWT令牌。
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class JwtRequestFilter extends OncePerRequestFilter {@Autowiredprivate JwtUtil jwtUtil;@Autowiredprivate CustomUserDetailsService customUserDetailsService;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {final String authorizationHeader = request.getHeader("Authorization");String username = null;String jwt = null;if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {jwt = authorizationHeader.substring(7);try {username = jwtUtil.extractUsername(jwt);} catch (ExpiredJwtException e) {logger.warn("JWT token has expired");}}if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = this.customUserDetailsService.loadUserByUsername(username);if (jwtUtil.validateToken(jwt, userDetails)) {UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);}}chain.doFilter(request, response);}
}
六、创建认证控制器
最后,创建一个控制器来处理认证请求。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AuthenticationController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JwtUtil jwtUtil;@Autowiredprivate CustomUserDetailsService customUserDetailsService;@PostMapping("/authenticate")public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception {authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword()));final UserDetails userDetails = customUserDetailsService.loadUserByUsername(authenticationRequest.getUsername());final String jwt = jwtUtil.generateToken(userDetails);return ResponseEntity.ok(new AuthenticationResponse(jwt));}
}
七、测试认证流程
你可以使用Postman或curl来测试认证流程。首先,发送一个POST请求到/authenticate端点,包含用户名和密码:
{"username": "admin","password": "password"
}
如果认证成功,你将收到一个JWT令牌。然后,你可以使用这个令牌访问其他受保护的端点,只需在请求头中添加Authorization: Bearer <JWT>。
八、总结
通过以上步骤,我们成功在Spring Boot项目中集成了JWT,实现了安全认证。JWT提供了一种无状态、可扩展的身份验证机制,非常适合分布式系统和微服务架构。希望本文能帮助你理解和实现JWT在Spring Boot中的应用。如果有任何问题,欢迎在评论区讨论!
相关文章:
如何在Spring Boot项目中集成JWT实现安全认证?
在Spring Boot项目中集成JWT实现安全认证是常见的需求。本文将详细介绍如何在Spring Boot项目中集成JWT,并通过一个完整的示例演示如何实现安全认证。 一、环境准备 首先,确保你的Spring Boot项目已经创建。然后,添加以下依赖到pom.xml文件…...
【 开发知识点 一 】 随机数生成器 /dev/urandom 和 /dev/random
文章目录 一、随机数生成器 是什么 ?二、为什么 需要 随机数生成器 ?三、随机数生成器 基本原理四、随机数生成器 三个输出接口五、随机生成器 应用1、简单应用2、项目应用一、随机数生成器 是什么 ? /dev/random 和 /dev/urandom 是 Linux 上的字符设备文件,它们是随机数…...
Python可视化大框架的研究与应用
## 摘要 随着数据科学和人工智能的快速发展,数据可视化成为了数据分析中不可或缺的一部分。Python作为一种功能强大且易于学习的编程语言,提供了多种可视化工具和库。本文旨在探讨Python可视化的主要框架,分析其特点、应用场景以及未来发展趋…...
Django ORM 的常用字段类型、外键关联的跨表引用技巧,以及 `_` 和 `__` 的使用场景
一、Django ORM 常用字段类型 1. 基础字段类型 字段类型说明示例CharField字符串字段,必须指定 max_lengthname models.CharField(max_length50)IntegerField整数字段age models.IntegerField()BooleanField布尔值字段is_active models.BooleanField()DateFiel…...
(动态规划 最长递增的子序列)leetcode 300
这道题我第一眼反应就是暴力,但是暴力的话就是n*n-1*n-2*...n-(n-1) 也就是O(n^n)dfs做绝对超时 贪心也不行,这里是子序列,要考虑在ni的范围内考虑多种路线取最优,所以用动态规划 如何用动态规划呢? 答:…...
小皮网站搭建
前提:小皮的安装下载 1、在www目录下创建一个新的文件夹,用来存放网站源码; 2、安装数据库管理工具phpMyadmin 3、新建数据表 添加字段 4、创建网站 5、前端的登录代码 注册 后端php 网页展示 登录成功跳转welcome.php...
3.16 AI Agent 技术全景解析:从核心能力到企业级应用实践
AI Agent 技术全景解析:从核心能力到企业级应用实践 关键词:AI Agent 技术架构, 大模型智能体开发, 自主决策系统设计, 模块化 Agent 设计, 企业级 Agent 应用 1. AI Agent 的本质定义与核心能力 AI Agent 是具备环境感知、自主决策和持续进化能力的智能系统,其核心特征可…...
【CSS—前端快速入门】CSS 常用样式
CSS 常用 CSS 样式 1. 前端样式查询网站: MDN Web Docs (mozilla.org) w3school 2. border 2.1 借助 MDN 了解 border 我们借助 MDN 网站来学习 border 样式的使用: 2.2 border 常见属性 保存代码,打开页面: 对于标签不同样式的…...
(七)消息队列-Kafka 序列化avro(传递)
(七)消息队列-Kafka 序列化avro(传递) 客从远方来,遗我双鲤鱼。呼儿烹鲤鱼,中有尺素书。 ——佚名《饮马长城窟行》 本文已同步CSDN、掘金平台、知乎等多个平台,图片依然保持最初发布的水印&…...
springboot使用redis
springboot使用redis redis-service.exe : 服务端,启动后不要关闭 redis-cli.exe : 客户端,访问redis中的数据 redisclient-win32.x86_64.2.0.jar : redis的图形界面客户端,执行方式是在这个文件的目录执行 java -jar redisclient-win32.x86_64.2.0.jar或者在这个jar包的目录…...
【原创】Open WebUI 本地部署
使用官网的默认部署,遇到不少的问题。比如白屏问题,其实需要修改几个参数即可。 其实在部署的时候有不少参数 WEBUI_AUTH False ENABLE_OPENAI_API 0 PATH /usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG C.UTF-8…...
【实战篇】【深度解析DeepSeek:从机器学习到深度学习的全场景落地指南】
一、机器学习模型:DeepSeek的降维打击 1.1 监督学习与无监督学习的"左右互搏" 监督学习就像学霸刷题——给标注数据(参考答案)训练模型。DeepSeek在信贷风控场景中,用逻辑回归模型分析百万级用户数据,通过特征工程挖掘出"凌晨3点频繁申请贷款"这类魔…...
SpringBoot高校运动会管理系统 附带详细运行指导视频
文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码1.报名赛事代码2.用户登录代码3.保存成绩代码 一、项目演示 项目演示地址: 视频地址 二、项目介绍 项目描述:这是一个基于SpringBoot框架开发的高校运动会管理系统项目。首先,这…...
【Linux网络-HTTP协议】HTTP基础概念+构建HTTP
代码定位:南毅c/Linux - Gitee.com HTTP协议 介绍 虽然我们说,应用层协议是我们程序猿自己定的.但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用。HTTP(超文本传输协议)就是其中之一。 在互联网世界中,…...
web3.0简介
Web3.0(或简称 Web3)是近年来广泛讨论的一个新型互联网概念,其核心思想在于利用区块链及相关分布式技术,打造一个更加开放、去中心化、透明且以用户为主导的网络生态系统。这意味着在 Web3.0 时代,用户不再只是信息的消…...
高频 SQL 50 题(基础版)_626. 换座位
高频 SQL 50 题(基础版)_626. 换座位 select(case when mod(id,2)!0 AND counts ! id then id1when mod(id,2)!0 AND counts id then idelse id -1end) as id,student fromseat,(selectcount(*) as countsfrom seat) as seat_counts order by id asc;...
hive 面试题
Hive基础概念 1.1 Hive是什么? 基于Hadoop的数据仓库工具,支持类SQL(HiveQL)查询,底层转换为MapReduce/Tez/Spark任务。 核心功能:数据ETL、查询、分析;定位:OLAP(分析…...
【Jenkins】个人向-Jenkinsfile如何写
官方参考:https://www.jenkins.io/doc/book/pipeline/syntax/ Pipeline Utility Steps 插件:https://birdbook.com.cn/ops/ci/jenkins/plugins/pipeline%20utility%20steps.html 常用环境变量 含义表达式备注params,传入参数传入参数params…...
python第十一课:并发编程 | 多任务交响乐团
🎯 本节目标 理解多线程/多进程/协程的应用场景掌握threading与multiprocessing核心用法学会使用asyncio进行异步编程开发实战项目:高并发爬虫引擎破解GIL锁的性能迷思 1️⃣ 并发编程三剑客 🎻 生活化比喻: 多线程 → 餐厅多个…...
Android SystemUI深度定制实战:下拉状态栏集成响铃功能开关全解析
一、功能实现全景视图 目标场景:在Android 14系统级ROM定制中,为SystemUI下拉状态栏的QuickQSPanel区域新增响铃模式切换开关,实现静音/响铃快速切换功能。该功能需通过三层关键改造实现: 二、核心实现三部曲 1. 配置注入&…...
基于 Flink CDC YAML 的 MySQL 到 Kafka 流式数据集成
本教程的演示都将在 Flink CDC CLI 中进行,无需一行 Java/Scala 代码,也无需安装 IDE。 这篇教程将展示如何基于 Flink CDC YAML 快速构建 MySQL 到 Kafka 的 Streaming ELT 作业,包含整库同步、表结构变更同步演示和关键参数介绍。 准备阶段…...
ubuntu下r8125网卡重启丢失修复案例一则
刚装的一台服务器,ubuntu24.04,主板网卡是r8125,安装服务后会莫名其妙丢失驱动 按照官网的方法下载最新8125驱动包: Realtek 然后卸载驱动 rmmod r8125 然后在驱动包里安装(幸好我之前装了build-essential&#x…...
解决 ERROR 1130 (HY000): Host is not allowed to connect to this MySQL server
当使用 MySQL 时,您可能会遇到错误信息“ERROR 1130 (HY000): Host ‘hostname’is not allowed to connect to this MySQL server”这是 MySQL 用于防止未经授权的访问的标准安全特性。实际上,服务器还没有配置为接受来自相关主机的连接。 Common Caus…...
科普|无人机专业术语
文章目录 前言一、飞控二、电调三、通道四、2S、3S、4S电池五、电池后面C是什么意思?六、电机的型号七、什么是电机的KV值?八、螺旋桨的型号九、电机与螺旋桨的搭配 前言 无人机飞控系统控制飞行姿态,电调控制电机转速,遥控器通道控制飞行动作。电池C…...
Qt:窗口
目录 菜单栏 QMenuBar 菜单添加快捷键 添加子菜单 添加分割线和添加图标 QMenuBar创建方式 工具栏 QToolBar 和菜单栏搭配 创建多个工具栏 状态栏 QStatusBar 状态栏中添加其他控件 浮动窗口 QDockWidget 对话框 对话框的内存释放问题 自定义对话框界面 模态对话…...
深入浅出 Go 语言:协程(Goroutine)详解
深入浅出 Go 语言:协程(Goroutine)详解 引言 Go 语言的协程(goroutine)是其并发模型的核心特性之一。协程允许你轻松地编写并发代码,而不需要复杂的线程管理和锁机制。通过协程,你可以同时执行多个任务,并…...
Python从0到100(八十九):Resnet、LSTM、Shufflenet、CNN四种网络分析及对比
前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…...
实验:k8s+keepalived+nginx+iptables
1、创建两个nginx的pod,app都是nginx nginx1 nginx2 2、创建两个的pod的service 3、配置两台keepalived的调度器和nginx七层反向代理,VIP设置192.168.254.110 keepalived调度器master keepalived调度器backup 两台调度器都配置nginx七层反向代理&#…...
elpis全栈课程学习之elpis-core学习总结
elpis全栈课程学习之elpis-core学习总结 核心原理 elpis-core是全栈框架elpis的服务端内核,主要应用于服务端接口的开发以及页面的SSR渲染,elpis-core基于约定优于配置的原理,通过一系列的loader来加载对应的文件,大大节约用户的…...
LlamaFactory-webui:训练大语言模型的入门级教程
LlamaFactory是一个开源框架,支持多种流行的语言模型,及多种微调技术,同时,以友好的交互式界面,简化了大语言模型的学习。 本章内容,从如何拉取,我已经搭建好的Llamafactory镜像开始࿰…...
