【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,一经查实,立即删除!

相关文章

Python 实现12306抢票脚本

我必须再次强调,使用或创建12306抢票脚本可能违反了12306网站的使用条款和条件,以及相关法律法规。因此,我不能提供任何关于如何编写或使用抢票脚本的具体代码或指导。 不过,我可以向您展示如何使用Python编写一个基本的网络爬虫来自动查询和预订火车票的基本步骤。但请注…

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

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

Python基础:【习题系列】多选题(一)

在Python中,哪些关键字用于流程控制? A. if B. function C. while D. for 答案:A, C, D 关于Python中的数据类型,以下哪些说法是正确的? A. 列表是可变的 B. 元组是不可变的 C. 字典可以使用可变数据类型作为键 D. 集合不允许重复元素 答案:A, B, D 在Python中,以下哪些…

排序算法(总结)-C++

排序算法 篇幅较长请耐心看完冒泡排序 ( B u b b l e S o r t Bubble Sort BubbleSort)选择排序 ( S e l e c t i o n S o r t Selection Sort SelectionSort)插入排序 ( I n s e r t i o n S o r t Insertion Sort InsertionSort)希尔排序 ( S h e l l S o r t Shell Sort She…

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方向综述、论文等成体系…

golang封装调用kafka的工具包

封装一个golang调用kafka的工具包&#xff0c;包含了consumer,producer,auth,在自己的生产环境上做过验证。可以做参考作用&#xff0c;也可以直接使用。 部分代码 // Run 执行消费动作 func (cg *ConsumerGroup) Run(ctx context.Context) {defer cg.close()for {select {ca…

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…

读书笔记--数据管理知识体系的阅读总结感悟

最近继续研读DAMA数据管理知识体系之数据管理章节,结合自身在应用系统建设、数据治理工作实践,有所感悟并记录如下,供大家参考。数据管理工作需要技术和非技术的双重技能,由业务人员和信息技术人员相互协作,共同来承担责任,确保组织管理的数据是高质量的,主要驱动力是使…

go语言实现简单ngnix样例

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

Chapter 1-17. Introduction to Congestion in Storage Networks

Q: Isn’t increasing network capacity the ultimate solution to network congestion? Increasing network capacity is the solution when a lack of network capacity is the root cause of congestion. There are many more reasons for network congestion and in thos…

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…

双目视觉(双目相机)

1.时间同步 需要一个单独的硬件&#xff08;单片机&#xff09;单独给每一个相机发送触发信息&#xff0c;然后再接收返回。 2.相机选型&#xff1a; &#xff08;1&#xff09;相机的分辨率 根据对图像精度的要求来选择相机的分辨率。 &#xff08;2&#xff09;颜色 通…

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\软件测…