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

news2025/3/9 22:42:43

前言

在企业级开发或者我们自己的课程设计中,确保用户数据的安全性和访问控制非常重要。而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.coloradmin.cn/o/1623516.html

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

相关文章

(C++) this_thread 函数介绍

文章目录 &#x1f6a9;前言⭐std::this_thread&#x1f579;️get_id()&#x1f5a5;️Code&#x1f516;get_id介绍&#x1f3f7;️其他介绍 &#x1f579;️sleep_for<>()&#x1f5a5;️Code&#x1f516;sleep_for介绍&#x1f3f7;️其他介绍 &#x1f579;️sleep…

第三节课,后端登录【1】

一、总任务 二、登录接口 get 请求&#xff0c;有缺陷&#xff0c;长度有限制 三、登录逻辑 四、代码书写位置 4.1 编写业务逻辑的位置 五、写代码 5.1 代码1 5.1.1 细节 按 CtrlAltShiftL ,快速格式化 5.1. 2 自动生成接口参数 先/** 再回车 效果图 5.2 按 alt enter …

数据结构练习-算法与时间复杂度

----------------------------------------------------------------------------------------------------------------------------- 1. 设n是描述问题规模的非负整数&#xff0c;下列程序段的时间复杂度是( )。 x0;while(n>(x1)*(x1)xx1; A.O(logn) B.O(n^(1/2)) C.O(n)…

ubuntu无法用快捷键启动终端(CTRL+AIT+T)

我的电脑不知道安装什么东西之后&#xff0c;就不能用快捷键&#xff08;CTRLAITT&#xff09;打开终端了 只能在文件夹内&#xff0c;点击鼠标右键选择终端&#xff0c;然后打开终端 一直这么用了几个月&#xff0c;今天实在受不了了&#xff0c;所以解决此问题 本文参考文章…

Seata 的AT模式写隔离问题,求大佬解答。

引用Seata 是什么&#xff1f; | Apache Seata AT 模式 前提​ 基于支持本地 ACID 事务的关系型数据库。Java 应用&#xff0c;通过 JDBC 访问数据库。 整体机制​ 两阶段提交协议的演变&#xff1a; 一阶段&#xff1a;业务数据和回滚日志记录在同一个本地事务中提交&…

岭回归(概念+实例)

目录 前言 一、基本概念 1. 引言 2. 岭回归的原理 3. 数学表达式 4. 岭回归的优点 5. 岭回归的局限性 6. 实际应用 二、具体实例 前言 “岭回归”这个词源于英文“Ridge Regression”&#xff0c;是一种用于处理回归分析中多重共线性&#xff08;multicollinearity&am…

java-spring-mybatis -学习第一天-基础知识讲解

目录 前置条件(创建一个项目) Mybatis 定义 可能出现的问题 这边如果连接不上数据库 ​编辑 Dao接口设计 Mybatis流程 创建实体类 User 和其属性 创建Mapper的接口类 测试类测试 实例数据库数据的更新 实例数据库数值的删除 最重要的是有一个原始的数据库 -我这边…

传统行业还在使用FTP传输?试试这套FTP替代传输解决方案!

在数字化转型的浪潮中&#xff0c;传统企业对文件传输的需求日益增长。然而&#xff0c;许多企业仍在使用传统的文件传输协议&#xff08;FTP&#xff09;来处理文件传输任务。尽管FTP在早期被广泛采用&#xff0c;但其固有的弊端逐渐成为企业发展的桎梏&#xff0c;所以找一个…

SQL中的锁

一、概述 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资(CPU、RAM、I/0)的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题&#xff0c;锁冲…

大模型 AI 框架昇思 MindSpore 2.3.RC1 发布,训练、推理性能大幅提升,JIT 编译强化

经过社区开发者们几个月的开发与贡献&#xff0c;现正式发布昇思 MindSpore2.3.RC1 版本&#xff0c;通过多维混合并行以及确定性 CKPT 来实现超大集群的高性能训练&#xff0c;支持大模型训推一体架构&#xff0c;大模型开发训练推理更简、更稳、更高效&#xff0c;并在训推一…

【CMU15-445 Part-19】Multi-Version Concurrency Control

Part19-Multi-Version Concurrency Control 其实说到底 MVCC不仅是一种并发控制协议&#xff0c;更是一个系统构建&#xff08;数据组织的方法&#xff09;。 简介 writer 不会 block readers&#xff0c;reader 也不会 block writers。只读事务可以读到一个consistent的sna…

nlp 自然语言处理的dataset数据库积累

下面的这个和 entity recognition有关的。 Weights & Biases

光伏无人机巡检主要有些什么功能和特点?

随着科技的飞速发展&#xff0c;无人机技术已经渗透到多个行业领域&#xff0c;光伏产业便是其中之一。光伏无人机巡检&#xff0c;作为一种新兴的巡检方式&#xff0c;正在逐渐取代传统的人工巡检&#xff0c;为光伏电站的安全、高效运行提供了有力保障。那么&#xff0c;光伏…

10:00面试,10:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

“我也想和月牙一样,把不满写在脸上”

贪吃蛇的初级实现 1. Win32 API介绍1.1 Win32 API1.2 控制台程序1.3 控制台屏幕上的坐标COORD1.4 GetStdHandle1.5 GetConsoleCursorInfo1.5.1 CONSOLE_CURSOR_INFO 1.6 SetConsoleCursorInfo1.7 SetConsoleCursorPosition1.8 GetAsyncKeyState 2. 贪吃蛇游戏设计与分析2.1 地图…

使用Shell终端访问Linux

一、实验目的 1、熟悉Linux文件系统访问命令&#xff1b; 2、熟悉常用 Linux Shell的命令&#xff1b; 3、熟悉在Linux文件系统中vi编辑器的使用&#xff1b; 4、进一步熟悉虚拟机网络连接模式与参数配置&#xff01; 二、实验内容 1、使用root帐号登陆到Linux的X-windows…

2024年了,还有必要搭建企业网站吗?

现在企业的营销手段五花八门。当下火爆的短视频直播平台展现出的裂变效应也取得不错的成绩&#xff0c;这不禁让很多企业舍弃做网站的念头&#xff0c;投入自媒体账号。那么&#xff0c;2024年了&#xff0c;还有必要搭建企业网站吗&#xff1f; 我们分两种企业来看&#xff1…

【11-Ⅱ】Head First Java 学习笔记

HeadFirst Java 本人有C语言基础&#xff0c;通过阅读Java廖雪峰网站&#xff0c;简单速成了java&#xff0c;但对其中一些入门概念有所疏漏&#xff0c;阅读本书以弥补。 第一章 Java入门 第二章 面向对象 第三章 变量 第四章 方法操作实例变量 第五章 程序实战 第六章 Java…

3d软件哪个适合新手学?3D动画渲染怎么好

在不同的行业领域&#xff0c;3D建模和动画的需求各异&#xff0c;因此所需的3D软件工具也会有所不同。对于刚开始接触3D设计的新手来说&#xff0c;软件的易操作性、丰富的学习资源以及与自己专业领域相关的功能是选择时的重要考虑因素。以下是几款适合初学者入门的3D软件推荐…

【第3节】“茴香豆“:搭建你的 RAG 智能助理

目录 1 基础知识1.1.RAG技术的概述1.2 RAG的基本结构有哪些呢&#xff1f;1.3 RAG 工作原理&#xff1a;1.4 向量数据库(Vector-DB )&#xff1a;1.5 RAG常见优化方法1.6RAG技术vs微调技术 2、茴香豆介绍2.1应用场景2.2 场景难点2.3 茴香豆的构建&#xff1a; 3 论文快读4 实践…