Spring Boot 整合SpringSecurity和JWT和Redis实现统一鉴权认证

news2024/11/29 4:45:38

📑前言

本文主要讲了Spring Security文章,如果有什么需要改进的地方还请大佬指出⛺️

🎬作者简介:大家好,我是青衿🥇
☁️博客首页:CSDN主页放风讲故事
🌄每日一句:努力一点,优秀一点

在这里插入图片描述

目录

文章目录

  • 📑前言
  • **目录**
    • 一、介绍
    • 二、主要功能
    • 三、原理
      • 1. SpringSecurity 过滤器链
      • 2. JWT校验登录的校验流程
    • 四、Spring Boot整合Redis、SpringSecurity、JWT的示例demo
  • 📑文章末尾


Spring Security

一、介绍

Spring Security是一个强大且高度可定制的身份验证和访问控制框架。它是保护基于Spring的应用程序的实际标准。Spring Security是一个可以为Java应用程序提供全面安全服务的框架。同时,它也可以轻松扩展以满足自定义需求。

二、主要功能

Authentication (认证),就是用户登录
Authorization (授权):一旦身份验证成功,判断用户拥有什么权限,可以访问什么资源
防止跨站请求伪造(CSRF):Spring Security提供了内置的防护机制,可以防止跨站请求伪造攻击。
密码存储:Spring Security提供了多种密码存储格式,包括明文、加密和哈希。
集成其他安全框架:Spring Security可以与其他安全框架如OAuth2、JWT等进行集成,以提供更全面的安全解决方案。

三、原理

​ SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。

1. SpringSecurity 过滤器链

在这里插入图片描述

SpringSecurity 采用的是责任链的设计模式,它有一条很长的过滤器链。

  • SecurityContextPersistenceFilter:每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中。
  • LogoutFilter:用于处理退出登录。
  • UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。
  • BasicAuthenticationFilter:检测和处理 http basic 认证。
  • ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException 。
  • FilterSecurityInterceptor:负责权限校验的过滤器,可以看做过滤器链的出口。

流程说明:客户端发起一个请求,进入 Security 过滤器链。
1.当到 LogoutFilter 的时候判断是否是登出路径,如果是登出路径则到 logoutHandler ,如果登出成功则到logoutSuccessHandler 登出成功处理,如果登出失败则由 ExceptionTranslationFilter ;如果不是登出路径则直接进入下一个过滤器。

2.当到 UsernamePasswordAuthenticationFilter 的时候判断是否为登录路径,如果是,则进入该过滤器进行登录操作,如果登录失败则到 AuthenticationFailureHandler 登录失败处理器处理,如果登录成功则到 AuthenticationSuccessHandler 登录成功处理器处理,如果不是登录请求则不进入该过滤器。

3.当到 FilterSecurityInterceptor 的时候会拿到 uri ,根据 uri 去找对应的鉴权管理器,鉴权管理器做鉴权工作,鉴权成功则到 Controller 层否则到 AccessDeniedHandler 鉴权失败处理器处理。

2. JWT校验登录的校验流程

在这里插入图片描述

首先前端一样是把登录信息发送给后端,后端查询数据库校验用户的账号和密码是否正确,正确的话则使用jwt生成token,并且返回给前端。以后前端每次请求时,都需要携带token,后端获取token后,使用jwt进行验证用户的token是否无效或过期,验证成功后才去做相应的逻辑。

四、Spring Boot整合Redis、SpringSecurity、JWT的示例demo

  1. 添加依赖项在 pom.xml 文件中添加以下依赖项:
   <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <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>
</dependencies>`
  1. 创建Redis配置类
@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory(new RedisStandaloneConfiguration(host, port));
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        final RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory());
        return template;
    }
}
  1. 创建 JwtTokenUtil 类,用于生成和验证JWT令牌。
@Component
public class JwtTokenUtil implements Serializable {

    private static final long serialVersionUID = -2550185165626007488L;

    private static final String secret = "mySecret";

    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    public <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();
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return doGenerateToken(claims, userDetails.getUsername());
    }

    private String doGenerateToken(Map<String, Object> claims, String subject) {
        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 5 * 60 * 60 * 1000))
                .signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
}` 
  1. 创建 JwtAuthenticationEntryPoint 类,用于处理未经授权的请求。
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

    private static final long serialVersionUID = -7858869558953243875L;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
                         AuthenticationException authException) throws IOException {

        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}` 
  1. 创建 JwtRequestFilter 类,用于解析和验证JWT令牌。
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            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 (IllegalArgumentException e) {
                System.out.println("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                System.out.println("JWT Token has expired");
            }
        } else {
            logger.warn("JWT Token does not begin with Bearer String");
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.myUserDetailsService.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);
            }
        }
        chain.doFilter(request, response);
    }
}` 
  1. 配置Spring Security
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    private UserDetailsService jwtUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
    }

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

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

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .authorizeRequests().antMatchers("/authenticate").permitAll().
                        anyRequest().authenticated().and().
                        exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}`

以上是简单的Spring Boot整合Redis、Security、JWT和Redis的示例,可以根据自己的实际需求进行调整。

📑文章末尾

在这里插入图片描述

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

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

相关文章

VPN网络环境下 本地客户端能连上mysql 本地启服务连不上mysql的原因

背景 公司mysql使用的是华为云RDS&#xff0c;由于要做一些测试验证&#xff0c;需要本地通过VPN直连华为RDS节点&#xff1b;找运维配置好网络后&#xff0c;本地 telnet 内网ip 3306 以及通过navicat客户端都能正常连接数据库&#xff1b;但是本地启动的服务就是连接不上。问…

【PyQt学习篇 · ⑩】:QAbstractButton的使用

文章目录 QAbstractButton简介子类化抽象类图标设置快捷键设置自动重复状态设置排他性点击设置点击有效区域可用信号 QAbstractButton简介 QAbstractButton 是一个抽象类&#xff0c;无法直接实例化&#xff0c;但它提供了很多在 PyQt 中使用按钮时常用的功能和特性。开发人员…

c++ 实现 AVL 树

AVL 树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家 G.M.Adelson-Velskii 和 E.M.Landis 在 1962 年发明了一…

实现Git增量代码的Jacoco覆盖率统计

今天我们给大家分享&#xff0c;如何使用Jacoco集合Git来做增量代码的覆盖率测试。实现的基本原理是&#xff1a; 使用Git的diff指令&#xff0c;计算出两个版本的差异&#xff1b;改造Jacoco源代码&#xff0c;只针对增量代码生成报告。 基本的功能滴滴的super-jacoco项目已…

使用Selenium IDE录制脚本

今天&#xff0c;我们开始介绍基于开源Selenium工具的Web网站自动化测试。 Selenium包含了3大组件&#xff0c;分别为&#xff1a;1. Selenium IDE 基于Chrome和Firefox扩展的集成开发环境&#xff0c;可以录制、回放和导出不同语言的测试脚本。 2. WebDriver 包括一组为不同…

2023年道路运输企业主要负责人证考试题库及道路运输企业主要负责人试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年道路运输企业主要负责人证考试题库及道路运输企业主要负责人试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人…

助力企业数智化转型,网易数帆是这样做的

伴随着云计算、大数据、人工智能等新兴技术的飞速发展&#xff0c;数字经济在国民经济中的重要性也变得愈发凸显。席卷全球的数字化和智能化浪潮不但深切地改变了人们的工作和生活方式&#xff0c;而且也给企业和组织带来了全新的发展机遇。 然而在数智化转型升级的道路上&…

免费外文文献检索网站,你一定要知道

01. Sci-Hub 网址链接&#xff1a;https://tool.yovisun.com/scihub/ Sci-hub是一个可以无限搜索、查阅和下载大量优质论文的数据库。其优点在于可以免费下载论文文献。 使用方法&#xff1a; 在Sci—hub搜索栏中粘贴所需文献的网址或者DOI&#xff0c;然后点击右侧的open即可…

分库分表自定义路由组件

1. 定义路由注解 Documented Retention(RetentionPolicy.RUNTIME) // Target用来表示注解作用范围&#xff0c;超过这个作用范围&#xff0c;编译的时候就会报错。 // Target(ElementType.TYPE)——接口、类、枚举、注解,Target(ElementType.METHOD)——方法 Target({Elem…

【Qt之事件过滤器】使用

介绍 事件过滤器是Qt中一种重要的机制&#xff0c;用于拦截并处理窗口和其他对象的事件。 它可以在不修改已有代码的情况下&#xff0c;动态地增加、删除一些处理事件的代码&#xff0c;并能够对特定对象的事件进行拦截和处理。 在Qt中&#xff0c;事件处理经过以下几个阶段&…

C++零散问题总结

什么是析构函数? return 0

图解Linux进程优先级

目录 1.什么是进程优先级&#xff1f; 2.进程优先级原理 3.查看进程优先级 4.修改进程优先级 4.1 setpriority函数原型 4.2 getpriority函数原型 4.3 sched_setscheduler函数原型 4.4 sched_getscheduler函数原型 4.5 sched_setparam函数原型 4.6 sched_getparam函数…

终极秘诀:打破无代码状态的小方法

终极秘诀&#xff1a;打破无代码状态的小方法 大家有没有遇到过不想写代码或学习的时候呢&#xff1f;这种情况下&#xff0c;你们会选择放松还是停下来呢&#xff1f;我很好奇大家是怎么度过这段时间的。我个人的情况是&#xff0c;当我不想写代码或学习的时候&#xff0c;我会…

Python基础入门例程39-NP39 字符串之间的比较(运算符)

最近的博文&#xff1a; Python基础入门例程38-NP38 牛牛的逻辑运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程37-NP37 不低于与不超过&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程36-NP36 谁的数字大&#xff08;运算符&#xff09;-CSD…

Hybrid App(原生+H5)开发

介绍 市面上主流的hybrid app框架主要有 React Native&#xff1a;由FaceBook开发&#xff0c;使用JavaScript和React来构建原生应用程序Flutter&#xff1a;由Google开发&#xff0c;使用Dart语言。Flutter使用自己的渲染引擎Ionic&#xff1a;基于 Web 技术&#xff08;HTM…

探索无限可能:APITable免费开源多维表格与可视化数据库远程访问的魅力

APITable免费开源的多维表格与可视化数据库公网远程访问 文章目录 APITable免费开源的多维表格与可视化数据库公网远程访问前言1. 部署APITable2. cpolar的安装和注册3. 配置APITable公网访问地址4. 固定APITable公网地址 前言 vika维格表作为新一代数据生产力平台&#xff0c…

【Java初阶练习题】-- 数组练习题

数组练习题 1. 创建的数组&#xff0c;并且赋初始值2. 改变原有数组元素的值3. 数组所有元素之和4. 奇数位于偶数之前5.两数之和6. 只出现一次的数字7. 多数元素8. 给你一个整数数组 arr&#xff0c;请你判断数组中是否存在连续三个元素都是奇数的情况&#xff1a;如果存在&…

Kibana中使用Dev Tools控制台创建索index索引同时添加date类型的时间参数(用于根据时间序列展示数据)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

android studio 字节码查看工具jclasslib bytecode viewer

jclasslib bytecode viewer 是一款非常好用的.class文件查看工具&#xff1b; jclasslib bytecode editor is a tool that visualizes all aspects of compiled Java class files and the contained bytecode. Many aspects of class files can be edited in the UI. In addit…

AD教程(六)现有元件模型的调用

AD教程&#xff08;六&#xff09;现有元件模型的调用 导入现有原理图 Altium Schematic Document (.SchDoc) 直接拖入AD即可 直接用现有原理图生成原理图库 点击设计&#xff0c;选择生成原理图库&#xff0c;进入归类设置界面&#xff08;用原理图直接生成原理图库&#xf…