Spring Boot用Spring Security + JWT + MySQL实现基于Token的身份认证

在现代Web应用中,安全是一个至关重要的议题。随着微服务架构和分布式系统的普及,传统的会话管理方式已经无法满足需求。JSON Web Tokens(JWT)作为一种无状态的、基于Token的认证机制,提供了一种安全、高效且易于扩展的解决方案。本文将介绍如何在Spring Boot应用中,结合Spring Security和MySQL数据库,实现基于JWT的身份认证。

JWT简介

JWT是一种紧凑、自包含的方式,用于在双方之间以JSON对象的形式安全地传输信息。它广泛应用于身份认证和授权。一个JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。

  • 头部通常包含两部分:令牌的类型(即JWT)和所使用的签名算法,如HMAC SHA256或RSA。

  • 载荷包含所要传递的信息。标准中注册的声明和公共的声明可以在此部分添加,例如用户ID(user_id)或角色(role)。

  • 签名用于验证消息在传输过程中没有被更改,并且,对于使用私钥签名的Token,还可以验证发送者的身份。

Spring Security与JWT

Spring Security是一个功能强大且高度可定制的认证和访问控制框架。它为Spring应用程序提供全面的安全服务,包括保护Web应用程序、REST API和微服务。

结合JWT和Spring Security,可以实现无状态的认证机制,其中JWT在客户端和服务器之间传递,用于验证用户的身份。

实现步骤

  1. 添加依赖:在Spring Boot项目的pom.xml文件中添加必要的依赖,包括Spring Security、Spring Data JPA和JWT库。

  2. 配置MySQL数据库:设置数据库并创建相应的用户表和角色表,以及用户角色关联表。

  3. 创建JPA实体:定义用户(User)和角色(Role)的JPA实体,并建立多对多的关系映射。

  4. 创建Spring Data JPA仓库:为用户和角色创建相应的仓库接口。

  5. JWT工具类:实现一个JWT工具类,提供生成和解析JWT的方法。

  6. Spring Security配置:配置Spring Security,定义认证管理器、用户详情服务和安全过滤器链。

  7. 创建DTO类:创建登录DTO和JWT认证响应DTO。

  8. 服务层:实现认证服务,用于处理登录请求和生成JWT。

  9. 控制器层:创建认证控制器,提供登录接口并返回JWT。

  10. SQL脚本:编写SQL脚本,初始化数据库数据。

  11. 测试:使用Postman或其他API测试工具测试登录接口和JWT认证。

示例代码

以下是一些关键组件的示例代码:

JwtTokenProvider.java

java
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;import java.util.Date;@Component
public class JwtTokenProvider {@Value("${app.jwt-secret}")private String jwtSecret;@Value("${app.jwt-expiration-milliseconds}")private long jwtExpirationDate;public String generateToken(Authentication authentication) {String username = authentication.getName();Date currentDate = new Date();Date expireDate = new Date(currentDate.getTime() + jwtExpirationDate);return Jwts.builder().setSubject(username).setIssuedAt(new Date()).setExpiration(expireDate).signWith(SignatureAlgorithm.HS512, jwtSecret).compact();}public String getUsername(String token) {return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject();}public boolean validateToken(String token) {try {Jwts.parser().setSigningKey(jwtSecret).parse(token);return true;} catch (Exception e) {return false;}}
}

JwtAuthenticationFilter.java

java
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.core.userdetails.UserDetailsService;
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate JwtTokenProvider jwtTokenProvider;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {final String authorizationHeader = request.getHeader("Authorization");String username = null;String jwt = null;if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {jwt = authorizationHeader.substring(7);username = jwtTokenProvider.getUsername(jwt);}if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {UserDetails userDetails = userDetailsService.loadUserByUsername(username);if (jwtTokenProvider.validateToken(jwt)) {UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));SecurityContextHolder.getContext().setAuthentication(authToken);}}filterChain.doFilter(request, response);}
}

SpringSecurityConfig.java

java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.crypto.bcrypt.BCryptPasswordEncoder;@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;@Autowiredprivate JwtAuthenticationFilter jwtAuthenticationFilter;@Beanpublic BCryptPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/api/auth/**").permitAll().anyRequest().authenticated().and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);}
}

总结

通过上述步骤和代码示例,你可以在Spring Boot应用中实现基于JWT的身份认证。这种方式不仅提高了应用的安全性,还增强了系统的可扩展性和性能。确保在实际部署时,使用HTTPS来保护Token的安全传输。

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

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

相关文章

小程序开发设计-小程序的宿主环境:组件⑦

上一篇文章导航: 小程序开发设计-小程序的宿主环境:宿主环境简介⑥-CSDN博客https://blog.csdn.net/qq_60872637/article/details/142425131?spm1001.2014.3001.5501 注:不同版本选项有所不同,并无大碍。 1.小程序中组件的分类…

深度学习(1):基础概念与创建项目

文章目录 基础概念创建项目1.在Anaconda上创建序虚拟环境2.创建PyProject3.创建完成 基础概念 CPU(中央处理器) CPU 是计算机的核心部件,负责执行计算和逻辑操作。它按照指令序列进行任务处理,擅长处理串行任务。CPU 的性能直接…

【MyBatis 源码拆解系列】MyBatis 运行原理 - 读取 xml 配置文件

欢迎关注公众号(通过文章导读关注:【11来了】),持续 分享大厂系统设计! 在我后台回复 「资料」 可领取编程高频电子书! 在我后台回复「面试」可领取硬核面试笔记! 文章导读地址:点击…

Nature:科研论文中正确使用ChatGPT的三个原则

我是娜姐 迪娜学姐 ,一个SCI医学期刊编辑,探索用AI工具提效论文写作和发表。 美国科罗拉多大学安舒茨医学院的生物医学信息学研究员Milton Pividori,一直在探索如何将ChatGPT等AI工具该技术融入课题组日常科研任务,例如进行文献综…

远程升级不成功?背后“凶手”可能是模组差分包…

最近有客户反馈在乡村里频繁出现掉线的情况。通过换货、换SIM卡对比排查测试,发现只有去年某批采购的那批模块在客户环境附近会出现掉线的情况,而今年采购的模块批次就不会掉线,很奇怪。 这个出问题的模块,就是合宙4G-Cat.1低功耗…

01.前端面试题之ts:说说如何在Vue项目中应用TypeScript?

文章目录 一、前言二、使用Componentcomputed、data、methodspropswatchemit 三 、总结 一、前言 与link类似 在VUE项目中应用typescript,我们需要引入一个库vue-property-decorator, 其是基于vue-class-component库而来,这个库vue官方推出…

数据驱动农业——农业中的大数据革命

橙蜂智能公司致力于提供先进的人工智能和物联网解决方案,帮助企业优化运营并实现技术潜能。公司主要服务包括AI数字人、AI翻译、埃域知识库、大模型服务等。其核心价值观为创新、客户至上、质量、合作和可持续发展。 橙蜂智农的智慧农业产品涵盖了多方面的功能&…

静态链接和动态链接的Golang二进制文件

关注TechLead,复旦博士,分享云服务领域全维度开发技术。拥有10年互联网服务架构、AI产品研发经验、团队管理经验,复旦机器人智能实验室成员,国家级大学生赛事评审专家,发表多篇SCI核心期刊学术论文,阿里云认…

抖音截流神器发布:不限量评论采集,实时推送,提升运营效率

在短视频风靡的今天,抖音成为品牌营销的新战场。如何在海量内容中脱颖而出,提升运营效率成为关键。本文将揭秘一款革命性的抖音运营工具,它不仅支持不限量评论采集,还实现了实时推送功能,助力运营者精准把握用户反馈&a…

保姆级 Stable Diffusion 教程,看完这篇就够了!

在美国科罗拉多州举办了一场新兴数字艺术家竞赛,一幅名为《太空歌剧院》的作品获得“数字艺术/数字修饰照片”类别的一等奖,神奇的是,该作品的作者并没有绘画基础,这幅画是他用 AI 生成的。 这让人们充分见识到AI 在绘画领域惊人的…

Shell实战(一)

Shell实战(一) 导语程序实例解压缩交互功能描述代码和运行结果实现解析 监视CPU和内存功能描述代码和运行结果实现解析 用户管理功能描述代码和运行结果实现解析 总结 导语 本篇引入三个书上的shell程序设计项目,由于书上的版本较老&#xf…

异构AI算力资源池:智能世界的新型基础设施

随着人工智能技术的飞速发展,AI应用对计算资源的需求日益增长。然而,传统的同构计算资源池无法满足AI应用对计算能力、能耗和成本的多样化需求。为此,异构AI算力资源池应运而生,成为未来智能世界的重要基础设施。 背 景 人工智能…

H3C交换机手动释放DHCP地址

原本的的配置,释放时间10天 导致所有的地址都被使用完 释放了地址池的地址 重新调整了超期时间为8小时

游戏行业数据集成“利器”

《黑神话:悟空》自公布以来,便在游戏界引起了巨大的轰动。这款游戏以其精湛的画面、精彩的剧情和深度的玩法,让无数玩家充满期待。而在其背后,游戏开发者们面临着诸多挑战,其中之一便是数据的集成与管理。竞争激烈的游…

【C++ Primer Plus习题】17.3

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: #include <iostream> #include <fstream> using namesp…

LeetCode Hot100 C++ 哈希 49.字母异位词分组

给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排…

2-99 基于matlab多尺度形态学提取眼前节组织

基于matlab多尺度形态学提取眼前节组织&#xff0c;通过应用不同尺度的结构元素进行边缘检测&#xff0c;再通过加权融合的思想来整合检测到的边缘&#xff0c;降低图像噪声的影响&#xff0c;提高边缘检测的精度。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&…

线程的状态及join()插队方法

一、线程的状态 线程整个生命周期中有6种状态&#xff0c;分别为 NEW 新建状态 、RUNNABLE 可运行状态、TERMINATED 终止状态、TIMED_WAITING计时等待状态、WAITING 等待状态、BLOCKED 阻塞状态 线程各个状态之间的转换&#xff1a; 在 JAVA 程序中&#xff0c;一个线程对象通过…

200Kg大载重多旋翼无人机应用前景详解

大载重多旋翼无人机是一类具备高载重能力和长航时特点的无人机系统&#xff0c;它们融合了多旋翼无人机的灵活性与大载重无人机的实用性&#xff0c;广泛应用于多个领域。 1. 航拍与影视制作 在航拍与影视制作领域&#xff0c;200Kg大载重多旋翼无人机凭借其出色的稳定性和载重…

维信诺三年半亏损近85亿:股价今年跌超四成,550亿大手笔投资8.6代

《港湾商业观察》施子夫 在显示面板领域知名度颇高的维信诺&#xff08;002387.SZ&#xff09;还是交出了持续亏损的半年报。从近些年财务数据上看&#xff0c;亏损似乎已经成为了公司甩不掉的包袱。 在盈利能力并不如预期的情况下&#xff0c;维信诺也对外释放要550亿扩产能…