SpringBoot 整合 Spring Security 、JWT 实现认证、权限控制

news2024/9/21 14:37:41

 ​

博客主页:     南来_北往

系列专栏:Spring Boot实战


前言

Spring Security 和 JWT 实现认证、权限控制是一种在Web应用中保障安全的重要手段

Spring Security是一个功能强大的身份验证和访问控制框架,它提供了完善的认证机制和方法级的授权功能。JWT(JSON Web Token)则是一种基于Token的认证方案,用于在通信双方之间传递安全信息。将Spring Security与JWT整合,可以实现有效的认证和权限管理,提升系统的安全性。

Spring Security的核心是一系列过滤器链,不同的功能经由不同的过滤器实现。例如,UsernamePasswordAuthenticationFilter负责登录认证处理,而FilterSecurityInterceptor则用于权限授权判断。这些过滤器形成了一道安全屏障,确保只有经过身份验证的用户才能访问应用程序的特定部分。

JWT在这种体系结构中扮演了重要角色。它是一种简洁且URL安全的方式,用于传递声明性陈述。一个JWT实际上就是一个字符串,由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部一般包含令牌的类型(例如JWT)和所使用的加密算法(如HMAC SHA256或RSA);载荷则包含了声明信息,例如用户ID、用户名和其他属性;签名则用于验证令牌的合法性,确保令牌在传输过程中未被篡改。

在生成JWT令牌时,可以使用对称加密(例如HMAC)或非对称加密(例如RSA)。对称加密使用相同的密钥进行加密和解密,而非对称加密则使用一对公钥和私钥。公钥加密的内容只能通过私钥解密,反之亦然。为了增加安全性,许多应用采用非对称加密算法,将公钥放在客户端,而将私钥保存在服务器端。

当用户成功登录后,服务器会生成一个JWT令牌并返回给客户端。客户端将该令牌存储在本地(例如浏览器的Local Storage),并在随后的请求中将其放在HTTP请求头的Authorization字段中发送给服务器。服务器接收到带有JWT的请求后,会通过一系列的过滤器来验证令牌的有效性。如果令牌有效且用户拥有相应的权限,请求将继续执行;否则,请求将被拒绝。

使用Spring Security和JWT进行认证及权限控制的优势在于其灵活性和扩展性。Spring Security提供了丰富的定制化选项,可以根据具体需求配置所需的过滤器和认证流程。同时,JWT的无状态特性使得系统易于扩展,特别是在微服务架构中,无需在不同服务间同步用户的会话信息。

综上所述,Spring Security结合JWT提供了一种高效且安全的认证和权限控制方案。通过理解其核心原理和正确配置相关组件,开发者可以构建出既安全又易维护的Web应用。

案例 

要在SpringBoot中整合Spring Security和JWT实现认证和权限控制,你需要按照以下步骤进行: 

1、在你的pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

 2、创建一个名为JwtUtil的工具类,用于生成和解析JWT令牌。

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;

public class JwtUtil {
    private static final String SECRET_KEY = "your_secret_key";
    private static final long EXPIRATION_TIME = 86400000L; // 1 day in milliseconds

    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public static String getUsernameFromToken(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }

    public static boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

 3、创建一个实现UserDetailsService接口的类,用于加载用户信息。

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;

@Service
public class CustomUserDetailsService implements UserDetailsService {
    // Load user from database or other data source
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // Implement your logic to load user details by username
        // For example, you can fetch user details from the database and return a UserDetails object
    }
}

4、创建一个名为SecurityConfig的配置类,继承WebSecurityConfigurerAdapter,并覆盖相应的方法。

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.method.configuration.EnableGlobalMethodSecurity;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

5、创建一个名为JwtRequestFilter的过滤器类,继承OncePerRequestFilter,并覆盖doFilterInternal方法。

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
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;

public class JwtRequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 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);
            username = JwtUtil.getUsernameFromToken(jwt);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            if (JwtUtil.validateToken(jwt)) {
                Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request, response);
    }
}

现在,你已经成功地在SpringBoot项目中整合了Spring Security和JWT,可以实现认证和权限控制。

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

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

相关文章

手机维修--学习笔记(一)

最近觉得手机主板维修比较有意思&#xff0c;观看许多师傅的维修视频&#xff0c;并做笔记如下&#xff1a; 手机主板维修&#xff1a; 【手机电路板怎么修&#xff0c;师傅对着电路图一步一步讲解&#xff0c;看完受益匪浅】https://www.bilibili.com/video/BV13A411v7wL?v…

梯度和反向传播

一.梯度 在机器学习的时候都了解过了&#xff0c;梯度是一个向量&#xff0c;导数变化最快的方向 损失函数&#xff1a; 通过梯度使损失降到最 用ywxb举例也就是使用梯度来更新w的值&#xff0c;ww-学习率*梯度。大于零就减小&#xff0c;反之增大 二.反向传播 就比如搭积木…

【源码+文档+调试讲解】古风生活体验交流网站

摘 要 二十一世纪我们的社会进入了信息时代&#xff0c;信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这一…

24/8/5算法笔记 逻辑回归sigmoid

今日是代码对sigmoid函数的实现和运用 #linear_model线性回归 #名字虽然叫逻辑回归&#xff0c;作用于分类 #分类&#xff1a;类别 #回归&#xff1a;预测 from sklearn.linear_model import LogisticRegression 实现函数 import numpy as np import matplotlib.pyplot as pl…

Linux笔记-3()

目录 一、Linuⅸ实操篇-定时任务调度 二、Linuⅸ实操篇-Linuⅸ磁盘分区、挂载 三、Linux实操篇-网络配置 一、Linuⅸ实操篇-定时任务调度 1 crond任务调度---crontab进行定时任务的设置1.1 概述任务调度&#xff1a;是指系统在某个时间执行的特定的命令或程序。任务调度分类…

【python】OpenCV—Image Colorization

文章目录 1、CIELAB 色彩空间2、作色问题定义3、Caffe 模型4、代码实现——Image5、代码实现——Video6、参考 1、CIELAB 色彩空间 Lab颜色空间&#xff0c;也称为Lab色彩空间或CIELAB色彩空间&#xff0c;是一种基于人类视觉感知特性的颜色模型。它是在1931年国际照明委员会&…

渗透SQL注入

首先打开php: Less-1: 打开浏览器输入网址&#xff0c;进入靶场&#xff1a; 输入?id1查询&#xff1a; 使用order by查询数据表的列数&#xff1a; http://127.0.0.1/sqllab/less-1/?id1 order by 4 -- ​ http://127.0.0.1/sqllab/less-1/?id1 order by 3 -- 由此可得表…

基于paddleocr实现验证码识别——训练数据

一、项目介绍 验证码&#xff08;CAPTCHA&#xff09;用于区分用户是人类还是计算机程序&#xff08;如机器人&#xff09;。这是为了防止各种形式的自动化攻击和滥用。以下是需要验证码识别的几个主要原因&#xff1a; 1. 防止恶意破解密码 攻击者可能会使用自动化程序进行…

数据结构----------贪心算法

什么是贪心算法&#xff1f; 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在问题求解过程中&#xff0c;每一步都采取当前状态下最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致最终的全局最优解的算法策略。 贪心算法的核心思想是做选择时&…

【深度学习】DeepSpeed,ZeRO 数据并行的三个阶段是什么?

文章目录 ZeRO实验实验设置DeepSpeed ZeRO Stage-2 实验性能比较进一步优化DeepSpeed ZeRO Stage-3 和 CPU 卸载结论ZeRO ZeRO(Zero Redundancy Optimizer)是一种用于分布式训练的大规模深度学习模型的优化技术。它通过分片模型状态(参数、梯度和优化器状态)来消除数据并行…

Flink异步IO 调用算法总是超时

记录一次使用Flink 异步调用IO 总是超时的bug 注&#xff1a;博主使用的版本就是&#xff1a;<flink.version>1.16.1</flink.version> 起因&#xff1a; 因公司业务需要&#xff0c;使用Flink对数据进行流式处理&#xff0c;具体处理流程就是&#xff0c;从kafka…

PageRank算法与TextRank算法

PageRank PageRank 是一种用于计算网页重要性的算法&#xff0c;其核心思想源自随机浏览模型。这个模型假设一个网络中的用户通过随机点击链接在网页之间跳转&#xff0c;并根据网页的链接结构计算每个网页的重要性。 假设三个网页按以下方式连接&#xff0c;计算每个网页的PR值…

【零基础实战】基于物联网的人工淡水湖养殖系统设计

文章目录 一、前言1.1 项目介绍1.1.1 开发背景1.1.2 项目实现的功能1.1.3 项目硬件模块组成1.1.4 ESP8266工作模式配置 1.2 系统设计方案1.2.1 关键技术与创新点1.2.2 功能需求分析1.2.3 现有技术与市场分析1.2.4 硬件架构设计1.2.5 软件架构设计1.2.6 上位机开发思路 1.3 系统…

Robot Operating System——深度解析单线程执行器(SingleThreadedExecutor)执行逻辑

大纲 创建SingleThreadedExecutor新增Nodeadd_nodetrigger_entity_recollectcollect_entities 自旋等待get_next_executablewait_for_workget_next_ready_executableTimerSubscriptionServiceClientWaitableAnyExecutable execute_any_executable 参考资料 在ROS2中&#xff0c…

ARM知识点二

一、指令 指令的生成过程 指令执行过程示例 if (a 0) {x 0; } else {x x 3; } //翻译为 cmp r0,#0 MOVEQ R1,#0 ADDGT R1,R1,#3指令获取&#xff1a;从Flash中读取 CMP R0, #0&#xff0c;控制器开始执行。 指令解码&#xff1a;解码器解析 CMP 指令&#xff0c;ALU比较R…

DAMA学习笔记(十)-数据仓库与商务智能

1.引言 数据仓库&#xff08;Data Warehouse&#xff0c;DW&#xff09;的概念始于20世纪80年代。该技术赋能组织将不同来源的数据整合到公共的数据模型中去&#xff0c;整合后的数据能为业务运营提供洞察&#xff0c;为企业决策支持和创造组织价值开辟新的可能性。与商务智能&…

浅谈线程组插件之jp@gc - Ultimate Thread Group

浅谈线程组插件之jpgc - Ultimate Thread Group jpgc - Ultimate Thread Group是JMeter的一个强大且灵活的扩展插件&#xff0c;由JMeter Plugins Project提供。它为性能测试提供了超越JMeter原生线程组的更精细的控制能力&#xff0c;允许用户根据复杂的场景设计自定义负载模…

【TFT电容屏】

TFT电容屏基础知识补课 前言一、入门知识1.1 引脚介绍1.1.1 显示部分片选指令选择写指令读操作复位并行数据接口 1.1.2 背光电源背光电源 1.1.3 触摸IIC接口外部中断接口复位NC 1.2 驱动介绍1.3 FSMC介绍 总结 前言 跟着阳桃电子的学习⇨逐个细讲触摸屏接口定义–STM32单片机…

科普文:JUC系列之ForkJoinPool源码解读ForkJoinWorkerThread

科普文&#xff1a;JUC系列之ForkJoinPool基本使用及原理解读-CSDN博客 科普文&#xff1a;JUC系列之ForkJoinPool源码解读概叙-CSDN博客 科普文&#xff1a;JUC系列之ForkJoinPool源码解读WorkQueue-CSDN博客 科普文&#xff1a;JUC系列之ForkJoinPool源码解读ForkJoinTask…

复现sql注入漏洞

Less-1 字符型注入 页面如下&#xff1a; 我们先输入“?id1”看看结果&#xff1a; 页面显示错误信息中显示提交到sql中的“1”在通过sql语句构造后形成“1" LIMIT 0, 1”&#xff0c;其中多了一个“”&#xff0c;那么&#xff0c;我们的任务就是——逃脱出单引号的控制…