【Spring Security系列】Spring Security整合JWT:构建安全的Web应用

前言

在企业级开发或者我们自己的课程设计中,确保用户数据的安全性和访问控制非常重要。而Spring Security和JWT是都两个强大的工具,它俩结合可以帮助我们实现这一目标。

Spring Security提供了全面的安全功能,而JWT则是一种用于身份验证的令牌机制。
在这里插入图片描述

JWT简单介绍

前面两个章节介绍过了Spring Security,这里就不再赘述了!!!

JWT是一种轻量级的身份验证和授权机制,通过发送包含用户信息的加密令牌来实现身份验证。这个工具我们在前面的文章中也提起过。

整合步骤与代码实现

目前大部分项目,大多数是使用前后端分离的模式。前后端分离的情况下,我们使用SpringSecurity解决权限问题的最常见的方案就是SpringSecurity+JWT 。

在这里插入图片描述

添加依赖
首先,我们需要在项目的pom.xml文件中添加Spring Security和JWT的依赖:

<!--JWT-->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.8.1</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
<!--工具包-->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.0.M3</version>
</dependency>
<dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version>
</dependency>

接下来配置Spring Security,在Spring Security配置类中,我们自定义用户详情服务和认证管理器,并配置HTTP安全策略:

@Configuration  
@EnableWebSecurity  
public class SecurityConfig extends WebSecurityConfigurerAdapter {  @Autowired  private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;  @Autowired  private JwtRequestFilter jwtRequestFilter;  @Autowired  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {  auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());  }  @Bean  @Override  public AuthenticationManager authenticationManagerBean() throws Exception {  return super.authenticationManagerBean();  }  @Bean  public PasswordEncoder passwordEncoder() {  return new BCryptPasswordEncoder();  }  @Override  protected void configure(HttpSecurity http) throws Exception {  http  .csrf().disable()  .authorizeRequests()  .antMatchers("/authenticate").permitAll()  .anyRequest().authenticated()  .and()  .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)  .and()  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);  http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);  }   
}

实现JWT生成和验证,我们创建一个JWT工具类,用于生成和解析JWT:

java
@Component  
public class JwtTokenUtil {  private String secret = "your_secret_key"; // 私钥,用于签名JWT  public String generateToken(UserDetails userDetails) {  Map<String, Object> claims = new HashMap<>();  return Jwts.builder()  .setClaims(claims)  .setSubject(((User) userDetails).getUsername())  .setIssuedAt(new Date(System.currentTimeMillis()))  .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10小时过期  .signWith(SignatureAlgorithm.HS512, secret)  .compact();  }  public String getUsernameFromToken(String token) {  return getClaimFromToken(token, Claims::getSubject);  }  public Date getExpirationDateFromToken(String token) {  return getClaimFromToken(token, Claims::getExpiration);  }  private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {  final Claims claims = getAllClaimsFromToken(token);  return claimsResolver.apply(claims);  }  private Claims getAllClaimsFromToken(String token) {  return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();  }  public boolean validateToken(String token, UserDetails userDetails) {  final String username = getUsernameFromToken(token);  return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));  }  private boolean isTokenExpired(String token) {  final Date expiration = getExpirationDateFromToken(token);  return expiration.before(new Date());

在这里插入图片描述

创建JWT过滤器与认证管理器

为了在用户每次请求时验证JWT,我们需要创建一个自定义的过滤器。同时,我们还需要一个认证管理器来处理用户的登录请求。

我们实现JWT过滤器

@Component  
public class JwtRequestFilter extends OncePerRequestFilter {  @Autowired  private JwtTokenUtil jwtTokenUtil;  @Autowired  private UserDetailsService userDetailsService;  @Override  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  throws ServletException, IOException {  final String requestTokenHeader = request.getHeader("Authorization");  String username = null;  String jwtToken = null;  if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {  jwtToken = requestTokenHeader.substring(7);  try {  username = jwtTokenUtil.getUsernameFromToken(jwtToken);  } catch (Exception e) {  logger.error("Unable to get JWT Token");  }  }  if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {  UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);  if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {  UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =  new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());  usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));  SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);  }  }  filterChain.doFilter(request, response);  }  
}

认证管理器,我们创建一个AuthenticationManager的实现来处理用户的登录请求:

@Service  
public class CustomAuthenticationManager implements AuthenticationManager {  @Autowired  private UserDetailsService userDetailsService;  @Autowired  private PasswordEncoder passwordEncoder;  @Override  public Authentication authenticate(Authentication authentication) throws AuthenticationException {  String username = authentication.getName();  String password = authentication.getCredentials().toString();  UserDetails userDetails = userDetailsService.loadUserByUsername(username);  if (userDetails == null) {  throw new BadCredentialsException("User not found");  }  if (!passwordEncoder.matches(password, userDetails.getPassword())) {  throw new BadCredentialsException("Wrong password");  }  return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());  }  
}

创建控制层LoginController

RestController  
@RequestMapping("/security")  
public class AuthenticationController {  @Autowired  private CustomAuthenticationManager authenticationManager;  @Autowired  private JwtTokenUtil jwtTokenUtil;  @Autowired  private UserDetailsService userDetailsService;  @PostMapping("/login")public ResponseEntity<?> createAuthenticationToken(@Valid @RequestBody LoginRequest loginRequest) throws Exception {  authenticate(loginRequest.getUsername(), loginRequest.getPassword());  final UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername());  final String token = jwtTokenUtil.generateToken(userDetails);  return ResponseEntity.ok(new JwtAuthenticationResponse(token));  }  private void authenticate(String username, String password) throws Exception {  try {  authenticationManager.authenticate(  new UsernamePasswordAuthenticationToken(username, password)  );  } catch (DisabledException e) {  throw new Exception("USER_DISABLED", e);  } catch (BadCredentialsException e) {  throw new Exception("INVALID_CREDENTIALS", e);  }  }  
}

使用ApiFox测试

在这里插入图片描述
这样,我们就可以构建一个安全且高效的Web应用了。

小结

Spring Security提供了强大的身份验证和授权功能,而JWT则提供了一种轻量级的令牌机制来验证用户身份。通过结合使用,我们可以实现无缝的用户身份验证和访问控制,然后保护我们应用的数据安全。

文章到这里就先结束了,后续会继续分享相关的知识点。
在这里插入图片描述

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

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

相关文章

小程序为什么必须安装SSL证书?怎么挑选?——建议收藏

小程序使用SSL证书的原因主要包括&#xff1a; 1. 安全要求&#xff1a;微信小程序等平台强制要求使用HTTPS加密协议&#xff0c;这意味着必须部署SSL证书以确保所有网络请求的安全性。没有SSL证书&#xff0c;小程序无法正常上线使用。 2. 数据加密&#xff1a;SSL证书通过加密…

51单片机入门(一)

1. 51单片机的基础介绍 2. RAM和ROM的区别 总体而言&#xff0c;RAM和ROM在计算机系统中起着不同的角色&#xff0c;RAM用于临时存储运行时数据&#xff0c;而ROM用于存储永久性的固件和系统程序。 3. 为什么叫51单片机 因为51系列单片机都是使用Intel 8031指令系统的单片机…

linux网络编程启动!(开端)

网络设计模式 &#xff1a;就两种模型 b/s 模型 : 浏览器—>服务器 优点是&#xff1a;跨平台。开发成本低 缺点是&#xff1a;网络通信的时候必须要使用http/https协议 http协议 是个应用层协议 不能在磁盘缓存或者从磁盘加载大量数据 http 与https 多了一层加密 c/s模型 …

C# Solidworks二次开发:访问平面、曲面相关API详解

大家好&#xff0c;今天要介绍的是关于平面、曲面相关的API。 下面是相关的API: &#xff08;1&#xff09;第一个为ISurfacePlanarFeatureData&#xff0c;这个API的含义为允许访问平面表面特征&#xff0c;下面是官方的具体解释&#xff1a; 下面是官方使用的例子&#xff…

美国站群服务器的配置选择要点?

美国站群服务器的配置选择要点? 随着互联网的快速发展&#xff0c;站群已经成为许多网站主和企业选择的一种有效的网络推广方式。而在搭建站群时&#xff0c;选择适合的服务器配置是至关重要的。美国作为全球互联网技术的先锋之一&#xff0c;拥有先进的服务器设施和强大的网…

【 书生·浦语大模型实战营】作业(四):XTuner 微调 LLM:1.8B、多模态、Agent

【 书生浦语大模型实战营】作业&#xff08;五&#xff09;&#xff1a;LMDeploy 量化部署 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系…

Linux——(关于权限常见的3个问题)

文章目录 1.修改文件或者目录的拥有者和所属组1.1chown指令1.2chgrp指令 2.常见的权限三个问题2.1对应一个目录&#xff0c;如果要进入&#xff0c;需要什么权限&#xff1f;2.2为什么我们创建的文件默认权限不是7772.2.1关于Linux下的权限掩码 2.3文件能否被删除取决于什么2.3…

Beyond Chain-of-Thought: A Survey of Chain-of-X Paradigms for LLMs论文阅读笔记(未完待续)

地址&#xff1a;https://arxiv.org/html/2404.15676v1 一些论文合集&#xff1a;https://github.com/atfortes/Awesome-LLM-Reasoning 背景 思维链 &#xff08;Chain-of-Thought&#xff0c;CoT&#xff09; 是一种被广泛采用的提示方法&#xff0c;它激发了大型语言模型 …

《HCIP-openEuler实验指导手册》2.1安装和测试Nginx

知识点 Nginx (发音为 “engine x”) 是一个开源的高性能 HTTP 和反向代理服务器&#xff0c;也是一个 IMAP/POP3/SMTP 代理服务器。由 Igor Sysoev 创建并维护&#xff0c;其设计用于处理高并发连接&#xff0c;具有高度的可扩展性和灵活性。 安装步骤 yum方式安装 dn…

go语言实现简单ngnix样例

目录 1、代码实现样例&#xff1a; 2、postman调用ngnix&#xff0c;转发&#xff1a; 1、代码实现样例&#xff1a; package mainimport ("bytes""encoding/json""io""log""net/http""net/http/httputil""…

ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

Python AI库 Pandas的常见操作的扩展知识

Python AI库 Pandas的常见操作的扩展知识 本文默认读者具备以下技能&#xff1a; 熟悉python基础知识&#xff0c;vscode或其它编辑工具 熟悉表格文件的基本操作 具备自主扩展学习能力 前文中对Pandas的数据结构以及基础操作做了介绍,本文中会在前文的基础上,对常见的操作进…

selenium拉动滚动条

selenium拉动滚动条 # 导包 from selenium import webdriver from time import sleep # 获取浏览器驱动对象 driver webdriver.Edge() # 最大化浏览器 driver.maximize_window() # 隐式等待 driver.implicitly_wait(30) # 打开url url r"C:\Users\黄永生\Desktop\软件测…

计算机找不到vcruntime140_1.dll,无法继续执行代码快速解决方法

vcruntime140_1.dll是一个重要的Windows操作系统中的动态链接库&#xff08;DLL&#xff09;文件&#xff0c;它是微软Visual C Redistributable软件包的组成部分。以下是该文件的详细介绍&#xff1a; 名称含义&#xff1a;“vcruntime”代表Visual C Runtime&#xff0c;表明…

static page 项目

static page 项目 作者&#xff1a;不染心 博客地址&#xff1a;https://blog.csdn.net/qq_38234785 源码地址&#xff1a;https://mbd.pub/o/bread/ZpWVlJps 未经允许&#xff0c;不得转载 文档版本v1&#xff0c;还没写完持续更新 一、引言 1. 软件概述和背景 本软件是…

STM32f103 HAL库读保护以及解除

读保护 void Flash_EnableReadProtection(void) {FLASH_OBProgramInitTypeDef OBInit;__HAL_FLASH_PREFETCH_BUFFER_DISABLE();HAL_FLASHEx_OBGetConfig(&OBInit);if(OBInit.RDPLevel OB_RDP_LEVEL_0){OBInit.OptionType | OPTIONBYTE_RDP;OBInit.RDPLevel OB_RDP_LEVEL…

FIR滤波器——DSP学习笔记三(包含一个滤波器设计的简明案例)

​​​​​​ 背景知识 FIR滤波器的特性与优点 可精确地实现线性相位响应&#xff08;Linear phase response&#xff09;&#xff0c;无相位失真&#xff1b; 总是稳定的&#xff0c;所有极点都位于原点 线性相位FIR滤波器的性质、类型及零点位置 冲击响应满足&#xff1a;奇…

【PyTorch】torch.gather() 用法

gather常被用于image做mask的操作中&#xff0c;对哪些地方进行赋值0/1 API&#xff1a; torch.gather — PyTorch 2.2 documentation torch.gather(input, dim, index, outNone) → Tensor gather()的意义&#xff1a; 顾名思义&#xff0c;聚集、集合&#xff1a;gather…

VS2019配合QT5.9开发IRayAT430相机SDK

环境配置 VS2019 QT5.9 编译器版本 MSVC2017_64添加系统环境变量&#xff08;完毕后重启电脑&#xff09; 从VS2019中下载Qt插件 从VS2019中添加单个编译组件 上述操作完成后用VS打开工程文件&#xff0c;工程文件地址 &#xff1a; C:\Users\86173\Desktop\IRCNETSDK_W…

数据分析:生存分析原理和应用实例

介绍 生存分析的目的是分析某个时间点的“生存概率”是多少。基于这样的研究目的,需要提供生存数据,它是一种由不同的开始时间和结束时间组成的事件-时间的数据,比如在癌症研究领域,研究手术到死亡的过程、治疗到疾病进展等等。 在开展生存分析前,需要了解什么是删失(c…