SpringBoot3响应式编程全套-Spring Security Reactive

news2024/11/28 6:47:32

目录

  • 传送门
  • 前言
  • 一、整合
  • 二、开发
    • 1、应用安全
    • 2、RBAC权限模型
  • 三、认证
    • 1、静态资源放行
    • 2、其他请求需要登录
  • 四、授权

传送门

SpringMVC的源码解析(精品)
Spring6的源码解析(精品)
SpringBoot3框架(精品)
MyBatis框架(精品)
MyBatis-Plus
SpringDataJPA
SpringCloudNetflix
SpringCloudAlibaba(精品)
Shiro
SpringSecurity
java的LOG日志框架
Activiti(敬请期待)
JDK8新特性
JDK9新特性
JDK10新特性
JDK11新特性
JDK12新特性
JDK13新特性
JDK14新特性
JDK15新特性
JDK16新特性
JDK17新特性
JDK18新特性
JDK19新特性
JDK20新特性
JDK21新特性
其他技术文章传送门入口

前言

由于面试问到的比较多,而且做java开发这块还是需要真正掌握的。
现有笔记尚硅谷雷锋阳老师的:SpringBoot3全栈指南,是我目前见过的最好笔记了。
参考视频尚硅谷雷锋阳老师的:SpringBoot零基础教程,面试&加薪必会,视频是24小时31分钟的高质量教程。
参考代码:https://gitee.com/leifengyang/spring-boot-3

最经典的20个Spring Boot面试题,95%以上会被问到,不服来战

为了防止雷锋阳老师的日志查看不到,这里分类整理一下。下面文章不定时更新

SpringBoot3核心特性-快速入门
SpringBoot3核心特性-Web开发
SpringBoot3核心特性-数据访问
SpringBoot3核心特性-基础特性
SpringBoot3核心特性-核心原理
SpringBoot3场景整合
SpringBoot3响应式编程全套-Reactor核心
SpringBoot3响应式编程全套-Spring Webflux
SpringBoot3响应式编程全套-R2DBC
SpringBoot3响应式编程全套-Spring Security Reactive

一、整合

在这里插入图片描述

目标:
SpringBoot + Webflux + Spring Data R2DBC + Spring Security

今日任务:
● RBAC权限模型
● WebFlux配置:@EnableWebFluxSecurity、@EnableReactiveMethodSecurity
● SecurityFilterChain 组件
● AuthenticationManager 组件
● UserDetailsService 组件
● 基于注解的方法级别授权

    <dependencies>
        <!-- https://mvnrepository.com/artifact/io.asyncer/r2dbc-mysql -->
        <dependency>
            <groupId>io.asyncer</groupId>
            <artifactId>r2dbc-mysql</artifactId>
            <version>1.0.5</version>
        </dependency>
        <!--        响应式 Spring Data R2dbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
        </dependency>

        <!--        响应式Web  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

二、开发

1、应用安全

● 防止攻击:
○ DDos、CSRF、XSS、SQL注入…
● 控制权限
○ 登录的用户能干什么。
○ 用户登录系统以后要控制住用户的所有行为,防止越权;
● 传输加密
○ https
○ X509
● 认证:
○ OAuth2.0
○ JWT

2、RBAC权限模型

Role Based Access Controll: 基于角色的访问控制

一个网站有很多用户: zhangsan
每个用户可以有很多角色:
一个角色可以关联很多权限:
一个人到底能干什么?
权限控制:
● 找到这个人,看他有哪些角色,每个角色能拥有哪些权限。 这个人就拥有一堆的 角色 或者 权限
● 这个人执行方法的时候,我们给方法规定好权限,由权限框架负责判断,这个人是否有指定的权限

所有权限框架:
● 让用户登录进来: 认证(authenticate):用账号密码、各种其他方式,先让用户进来
● 查询用户拥有的所有角色和权限: 授权(authorize): 每个方法执行的时候,匹配角色或者权限来判定用户是否可以执行这个方法
导入Spring Security:默认效果

三、认证

登录行为

1、静态资源放行

2、其他请求需要登录

package com.atguigu.security.config;

import com.atguigu.security.component.AppReactiveUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;

/**
 * @author lfy
 * @Description
 * @create 2023-12-24 21:39
 */
@Configuration
@EnableReactiveMethodSecurity //开启响应式 的 基于方法级别的权限控制
public class AppSecurityConfiguration {


    @Autowired
    ReactiveUserDetailsService appReactiveUserDetailsService;

    @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        //1、定义哪些请求需要认证,哪些不需要
        http.authorizeExchange(authorize -> {
            //1.1、允许所有人都访问静态资源;
            authorize.matchers(PathRequest.toStaticResources()
                    .atCommonLocations()).permitAll();


            //1.2、剩下的所有请求都需要认证(登录)
            authorize.anyExchange().authenticated();
        });

        //2、开启默认的表单登录
        http.formLogin(formLoginSpec -> {
//            formLoginSpec.loginPage("/haha");
        });

        //3、安全控制:
        http.csrf(csrfSpec -> {
            csrfSpec.disable();
        });

        // 目前认证: 用户名 是 user  密码是默认生成。
        // 期望认证: 去数据库查用户名和密码

        //4、配置 认证规则: 如何去数据库中查询到用户;
        // Sprinbg Security 底层使用 ReactiveAuthenticationManager 去查询用户信息
        // ReactiveAuthenticationManager 有一个实现是
        //   UserDetailsRepositoryReactiveAuthenticationManager: 用户信息去数据库中查
        //   UDRespAM 需要  ReactiveUserDetailsService:
        // 我们只需要自己写一个 ReactiveUserDetailsService: 响应式的用户详情查询服务
        http.authenticationManager(
                new UserDetailsRepositoryReactiveAuthenticationManager(
                        appReactiveUserDetailsService)
        );



//        http.addFilterAt()





        //构建出安全配置
        return http.build();
    }


    @Primary
    @Bean
    PasswordEncoder passwordEncoder(){

        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        return encoder;
    }
}

在这里插入图片描述
这个界面点击登录,最终Spring Security 框架会使用 ReactiveUserDetailsService 组件,按照 表单提交的用户名 去数据库查询这个用户详情(基本信息[账号、密码],角色,权限);
把数据库中返回的 用户详情 中的密码 和 表单提交的密码进行比对。比对成功则登录成功;

package com.atguigu.security.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * @author lfy
 * @Description
 * @create 2023-12-24 21:57
 */
@Component  // 来定义如何去数据库中按照用户名查用户
public class AppReactiveUserDetailsService implements ReactiveUserDetailsService {


    @Autowired
    DatabaseClient databaseClient;

    // 自定义如何按照用户名去数据库查询用户信息

    @Autowired
    PasswordEncoder passwordEncoder;
    @Override
    public Mono<UserDetails> findByUsername(String username) {


//        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        //从数据库查询用户、角色、权限所有数据的逻辑
        Mono<UserDetails> userDetailsMono = databaseClient.sql("select u.*,r.id rid,r.name,r.value,pm.id pid,pm.value pvalue,pm.description " +
                        "from t_user u " +
                        "left join t_user_role ur on ur.user_id=u.id " +
                        "left join t_roles r on r.id = ur.role_id " +
                        "left join t_role_perm rp on rp.role_id=r.id " +
                        "left join t_perm pm on rp.perm_id=pm.id " +
                        "where u.username = ? limit 1")
                .bind(0, username)
                .fetch()
                .one()// all()
                .map(map -> {
                    UserDetails details = User.builder()
                            .username(username)
                            .password(map.get("password").toString())
                            //自动调用密码加密器把前端传来的明文 encode
//                            .passwordEncoder(str-> passwordEncoder.encode(str)) //为啥???
                            //权限
//                            .authorities(new SimpleGrantedAuthority("ROLE_delete")) //默认不成功
                            .roles("admin", "sale","haha","delete") //ROLE成功
                            .build();

                    //角色和权限都被封装成 SimpleGrantedAuthority
                    // 角色有 ROLE_ 前缀, 权限没有
                    // hasRole:hasAuthority
                    return details;
                });

        return userDetailsMono;
    }
}

四、授权

@EnableReactiveMethodSecurity

package com.atguigu.security.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

/**
 * @author lfy
 * @Description
 * @create 2023-12-24 21:31
 */
@RestController
public class HelloController {


    @PreAuthorize("hasRole('admin')")
    @GetMapping("/hello")
    public Mono<String> hello(){

        return Mono.just("hello world!");
    }


    // 角色 haha: ROLE_haha:角色
    // 没有ROLE 前缀是权限

    //复杂的SpEL表达式
    @PreAuthorize("hasRole('delete')")
    @GetMapping("/world")
    public Mono<String> world(){
        return Mono.just("world!!!");
    }
}

官方实例:
https://github.com/spring-projects/spring-security-samples/tree/main

配置是: SecurityWebFilterChain

package com.atguigu.security.config;

import com.atguigu.security.component.AppReactiveUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;

/**
 * @author lfy
 * @Description
 * @create 2023-12-24 21:39
 */
@Configuration
@EnableReactiveMethodSecurity //开启响应式 的 基于方法级别的权限控制
public class AppSecurityConfiguration {


    @Autowired
    ReactiveUserDetailsService appReactiveUserDetailsService;

    @Bean
    SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        //1、定义哪些请求需要认证,哪些不需要
        http.authorizeExchange(authorize -> {
            //1.1、允许所有人都访问静态资源;
            authorize.matchers(PathRequest.toStaticResources()
                    .atCommonLocations()).permitAll();


            //1.2、剩下的所有请求都需要认证(登录)
            authorize.anyExchange().authenticated();
        });

        //2、开启默认的表单登录
        http.formLogin(formLoginSpec -> {
//            formLoginSpec.loginPage("/haha");
        });

        //3、安全控制:
        http.csrf(csrfSpec -> {
            csrfSpec.disable();
        });

        // 目前认证: 用户名 是 user  密码是默认生成。
        // 期望认证: 去数据库查用户名和密码

        //4、配置 认证规则: 如何去数据库中查询到用户;
        // Sprinbg Security 底层使用 ReactiveAuthenticationManager 去查询用户信息
        // ReactiveAuthenticationManager 有一个实现是
        //   UserDetailsRepositoryReactiveAuthenticationManager: 用户信息去数据库中查
        //   UDRespAM 需要  ReactiveUserDetailsService:
        // 我们只需要自己写一个 ReactiveUserDetailsService: 响应式的用户详情查询服务
        http.authenticationManager(
                new UserDetailsRepositoryReactiveAuthenticationManager(
                        appReactiveUserDetailsService)
        );







        //构建出安全配置
        return http.build();
    }


    @Primary
    @Bean
    PasswordEncoder passwordEncoder(){

        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        return encoder;
    }
}

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

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

相关文章

云+AI 时代的 OceanBase

2024 年 10 月 23 日&#xff0c;OceanBase 年度发布会在北京成功举办。会上&#xff0c;CEO 杨冰表示&#xff0c;OceanBase将继续践行一体化产品战略&#xff0c;不断演进产品能力&#xff0c;从支撑关键业务负载的OLTP能力&#xff0c;到实时分析的AP能力&#xff0c;再到应…

Unity Apple Vision Pro 保姆级开发教程 - Simulator 模拟器使用

教程视频 Apple VisionPro Simulator 模拟器使用教程 Unity Vision Pro 中文课堂教程地址&#xff1a; Unity3D Vision Pro 开发教程【保姆级】 | Unity 中文课堂 ​ VsionOS Simulator 简介 visionOS Simulator 是一个用于开发和测试 visionOS 应用程序的工具。它模拟 Appl…

Return code 0x40450037 (Not a valid nxos image)

1.问题描述 硬件&#xff1a;C93180YC&#xff08;Nexus NXOS&#xff09; 软件版本&#xff1a;Release 9.3.8 需要描述&#xff1a;需要将Nexus93180从Release 9.3.8升级到10.3.6&#xff08;M&#xff09;&#xff0c;在执行操作的时候&#xff0c;发现如下问题&#xff…

从0到1学习node.js(npm)

文章目录 一、NPM的生产环境与开发环境二、全局安装三、npm安装指定版本的包四、删除包 五、用npm发布一个包六、修改和删除npm包1、修改2、删除 一、NPM的生产环境与开发环境 类型命令补充生产依赖npm i -S uniq-S 等效于 --save -S是默认选项npm i -save uniq包的信息保存在…

[实时计算flink]基于Paimon的数据库实时入湖快速入门

Apache Paimon是一种流批统一的湖存储格式&#xff0c;支持高吞吐的写入和低延迟的查询。本文通过Paimon Catalog和MySQL连接器&#xff0c;将云数据库RDS中的订单数据和表结构变更导入Paimon表中&#xff0c;并使用Flink对Paimon表进行简单分析。 背景信息 Apache Paimon是一…

Elasticsearch如何搜索日志并存储

Elasticsearch 是一个分布式搜索引擎&#xff0c;擅长对大量数据进行实时的搜索、分析和存储。它常被用于处理日志数据&#xff0c;配合工具如 Logstash 或 Filebeat 来收集和存储日志&#xff0c;并提供强大的搜索和分析能力。接下来&#xff0c;我将解释 Elasticsearch 如何处…

8年经验之谈 —— 如何使用自动化工具编写测试用例?

以下为作者观点&#xff0c;仅供参考&#xff1a; 在快速变化的软件开发领域&#xff0c;保证应用程序的可靠性和质量至关重要。随着应用程序复杂性和规模的不断增加&#xff0c;仅手动测试 无法满足行业需求。 这就是测试自动化发挥作用的地方&#xff0c;它使软件测试人员…

NVR小程序接入平台/设备EasyNVR多个NVR同时管理的高效解决方案

在当今的数字化安防时代&#xff0c;视频监控系统的需求日益复杂和多样化。为了满足不同场景下的监控需求&#xff0c;一种高效、灵活且兼容性强的安防视频监控平台——NVR批量管理软件/平台EasyNVR应运而生。本篇探讨这一融合所带来的创新与发展。 一、NVR监测软件/设备EasyNV…

【设计模式】MyBatis 与经典设计模式:从ORM到设计的智慧

作者&#xff1a;后端小肥肠 &#x1f347; 我写过的文章中的相关代码放到了gitee&#xff0c;地址&#xff1a;xfc-fdw-cloud: 公共解决方案 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 【设计模式】揭秘Spri…

vue2 el-select赋值无效(无法选中)

背景&#xff1a;点击添加明细时&#xff0c;el-table会新增一条数据&#xff0c;其中&#xff0c;存货原申购用途 会根据 费用承担事业部 下拉框的值改变而改变&#xff0c;所以每次费用承担事业部发生变化时&#xff0c;都需要清空存货原申购用途的值 最开始是直接这样写的&a…

D. Deleting Divisors

传送门&#xff1a;Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a;博弈论 打表找规律&#xff08; 递推 &#xff09; 如果 ans[i] 为 true &#xff0c;则 Alice 能赢 ans[i] 为 false&#xff0c;则 Bob 会赢 数字 n 的一个因子 为 x &#xff0c; 如果 …

【简历】25届浙江某211大学JAVA简历:明明项目有货,但是长篇大论减分!!

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 另外&#xff1a;我们出这一系列校招简历指导的原因&#xff0c;就是看很多学生被忽悠&#xff0c;没有先定位大厂、中厂还是小公司&#xff0c;导…

【日志】力扣刷题——买卖股票的最佳时机 // Unity——添加数据表文件、EPPlus插件以及编辑器开发生成Excel转Json代码文件复习

2024.10.17 【力扣刷题】 两题连一起&#xff0c;思路很像 121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 122. 买卖股票的最佳时机 II - 力扣&#xff08;LeetCode&#xff09; 121. 买卖股票的最佳时机 按照顺序查找&#xff0c;找到最大的差值时&#x…

Prompt-Tuning方法学习

文章目录 一、背景1.1 Pre-training1.2 Fine-Tuning1.3 高效微调&#xff08;SOTA PEFT&#xff09;1.4 基于强化学习的进阶微调方法&#xff08;RLHF&#xff09; 二、Prompt-Tuning技术2.1 发展历程2.2 Prompt模板构建方式 三、基于连续提示的Prompt Tuning四、Q&A 一、背…

【升华】一文从0到1到实际性应用大语言模型(LLM)

一、前言 相信网已经很多LLM大模型 的介绍 &#xff0c;概念&#xff0c;发展历史&#xff0c;应用场景的很多文章&#xff0c;但是很多文章都是缺少细节的描述&#xff0c;到底怎么用&#xff0c;需要些什么东西怎么层显出来。所以虽然看了很多大模型的介绍&#xff0c;也仅仅…

【Linux篇】初学Linux,如何快速搭建Linux开发环境

文章目录 前言1. Linux背景介绍1.1 UNIX的发展历史1.2 Linux的发展历史 2. 企业应用现状3. 开源3.1 探索Linux源代码3.2 开源 VS 闭源 4. Linux的版本4.1 技术线4.2 商业产品线 5. os概念&#xff0c;定位6. 搭建Linux环境6.1 Linux环境的搭建方式6.2 购买云服务器 7. 使用XShe…

从一个简单的计算问题,看国内几个大语言模型推理逻辑能力

引言 首先&#xff0c;来看问题&#xff1a; 123456*987654等于多少&#xff0c;给出你计算的过程。 从openai推出chatgpt以来&#xff0c;大模型发展的很快&#xff0c;笔者也经常使用免费的大语言模型辅助进行文档编写和编码工作。大模型推出时间也好久了&#xff0c;笔者想…

红队-安全见闻篇(上)

声明 学习视频来自B站UP主 泷羽sec的个人空间-泷羽sec个人主页-哔哩哔哩视频,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 一.编程与开发 1.后端语言学习 C语⾔&#xff1a;⼀种通⽤的…

[解决]在Arduino IDE 打开 ino 类型文件处于read only editor模式

今天打开一个ino类型文件发现这个问题&#xff0c;无法编辑…… 解决方法&#xff1a;右键点击ino类型文件&#xff08;你打开的那个&#xff09;进入属性栏 发现只读被勾上&#xff0c;取消打勾并点击最下方的确认 现在就可以编辑啦

Unity目录居然这么写就不会被引入到项目内

只要加一个小符号~ 这是一个约定俗成的符号么~~~~ 当然&#xff0c;代码管理器还是识别的 也&#xff0c;只要稍微加一些规则&#xff0c;去避免代码入库 只要一天不死&#xff0c;还是能在程序员这个座位上看到新的东西 什么时候才到尽头&#xff1f;&#xff1f;&#xff1f…