当前位置: 首页 > news >正文

Reactor 响应式编程(第四篇:Spring Security Reactive)

系列文章目录

Reactor 响应式编程(第一篇:Reactor核心)
Reactor 响应式编程(第二篇:Spring Webflux)
Reactor 响应式编程(第三篇:R2DBC)
Reactor 响应式编程(第四篇:Spring Security Reactive)


文章目录

  • 系列文章目录
  • 1. 整合
  • 2. 开发
    • 2.1 应用安全
    • 2.2 RBAC权限模型
  • 3. 认证
    • 3.1 静态资源放行
    • 3.2 其他请求需要登录
  • 4. 授权


1. 整合

目标:
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>

2. 开发

2.1 应用安全

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

2.2 RBAC权限模型

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


一个网站有很多用户: zhangsan
每个用户可以有很多角色
一个角色可以关联很多权限
一个人到底能干什么?

权限控制:

  • 找到这个人,看他有哪些角色,每个角色能拥有哪些权限。 这个人就拥有一堆的 角色 或者 权限
  • 这个人执行方法的时候,我们给方法规定好权限,由权限框架负责判断,这个人是否有指定的权限

所有权限框架:

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

导入Spring Security:默认效果


3. 认证

3.1 静态资源放行

3.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 {@AutowiredReactiveUserDetailsService appReactiveUserDetailsService;@BeanSecurityWebFilterChain 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@BeanPasswordEncoder 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 {@AutowiredDatabaseClient databaseClient;// 自定义如何按照用户名去数据库查询用户信息@AutowiredPasswordEncoder passwordEncoder;@Overridepublic 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:hasAuthorityreturn details;});return userDetailsMono;}
}

4. 授权

@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!!!");}
}

官方实例
配置是: 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 {@AutowiredReactiveUserDetailsService appReactiveUserDetailsService;@BeanSecurityWebFilterChain 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@BeanPasswordEncoder passwordEncoder(){PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();return encoder;}
}

相关文章:

Reactor 响应式编程(第四篇:Spring Security Reactive)

系列文章目录 Reactor 响应式编程&#xff08;第一篇&#xff1a;Reactor核心&#xff09; Reactor 响应式编程&#xff08;第二篇&#xff1a;Spring Webflux&#xff09; Reactor 响应式编程&#xff08;第三篇&#xff1a;R2DBC&#xff09; Reactor 响应式编程&#xff08…...

JVM 双亲委派模型以及垃圾回收机制

目录 1. JVM 内存区域划分 2. JVM 中类加载的过程 1) 类加载的基本流程 2) 双亲委派模型 3. JVM 中垃圾回收机制 1) 找到垃圾 a) 引用计数 b) 可达性分析 2) 释放垃圾 1. JVM 内存区域划分 一个运行起来的 Java 进程&#xff0c;其实就是一个 JVM 虚拟机。 而进程是…...

Delphi编写涂鸦桌面的小程序

用Delphi编写涂鸦桌面的小程序&#xff0c;类似于腾讯会议中的画板功能的实现。这里用Delphi实现代码给大家提供一些思路&#xff1b; 首先&#xff0c;新建一个Application&#xff0c;将Form1的WindowState设为wsMaximized&#xff0c;BorderStyle设为bsNone。这样做的目的就…...

智星云技术文档:GPU测速教程

安装gpu burn git clone https://github.com/wilicc/gpu-burn cd gpu-burn/ make测试 ./gpu_burn 60100.0% procd: 14280 (7373 Gflop/s) - 13390 (6997 Gflop/s) - 15912 (7110 Gflop/s) - 13184 (7055 Gflop/s) - 13464 (7369 Gflop/s) - 13974 (7351 Gflop/s) - 16626 (7…...

《Kali Linux 软件源更换攻略:优化软件获取与系统更新》

KALI为什么要换源 速度提升 Kali Linux 默认的软件源服务器通常位于国外。在从这些国外源下载软件包、更新系统时&#xff0c;会受到网络带宽、网络延迟等因素的限制。例如&#xff0c;在中国&#xff0c;连接到国外服务器的网络速度可能较慢&#xff0c;尤其是在下载大型软件…...

C# 在dataview可以直接增删改查mysql数据库

C# 在dataview可以直接增删改查mysql数据库 首先&#xff0c;确保你的项目中已经安装了MySql.Data。你可以通过NuGet包管理器安装它&#xff1a; Install-Package MySql.Data -Version 8.0.28using System; using System.Data; using MySql.Data.MySqlClient;public class My…...

C#—泛型约束

C#—泛型约束 概念&#xff1a; 泛型约束就是告知编译器类型参数必须具备的功能。 在没有任何约束的情况下&#xff0c;类型参数可以是任何类型。 编译器只能假定 System.Object 的成员&#xff0c;它是任何 .NET 类型的最终基类。当分配给泛型的类型参数不满足约束的类型时&…...

MeiliSearch:一款轻量级开源搜索引擎

Meilisearch 是由 Meili &#xff08;一家总部位于法国的软件开发公司&#xff09;创建的搜索引擎&#xff0c;目前在 Github 上有 47.9k stars。 Meillisearch 具备以下特色功能&#xff08;ChatGPT-4o 翻译&#xff09;&#xff1a; 混合搜索&#xff1a;结合语义搜索和全文…...

Ansible playbook 详解与实战操作

一、概述 playbook 与 ad-hoc 相比,是一种完全不同的运用 ansible 的方式&#xff0c;类似与 saltstack 的 state 状态文件。ad-hoc 无法持久使用&#xff0c;playbook 可以持久使用。 playbook 是由一个或多个 play 组成的列表&#xff0c;play 的主要功能在于将事先归并为一…...

青少年夏令营管理系统的设计与开发(社团管理)(springboot+vue)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...

加速合并,音频与字幕的探讨

因上一节。合并时速度太慢了。显卡没用上。所以想快一点。1分钟的视频用了5分钟。 在合并视频时,进度条中的 now=None 通常表示当前处理的时间点没有被正确记录或显示。这可能是由于 moviepy 的内部实现细节或配置问题。为了加快视频合并速度并利用 GPU 加速,可以采取以下措…...

Uniapp插件如何通过NFC读取多种证卡信息?

nfc读卡uniapp插件&#xff0c;由中软高科进行开发&#xff0c;主要是通过NFC读取居民身份证、港澳台居住证、外国人居住证、护照等证卡的信息。经过多个版本的升级更新&#xff0c;目前性能已趋于稳定&#xff0c;并且读卡速度较之最初版本有了大的提升。 注意事项 测试使用的…...

米哈游C++开发精选60道面试题及参考答案

C++ 面向对象的三个特征 封装是把数据和操作数据的函数捆绑在一起,并且对数据的访问进行限制。这样做的好处是可以隐藏对象的内部实现细节,只暴露必要的接口给外部。例如,在一个银行账户类中,账户余额这个数据成员是被封装起来的,外部不能直接访问和修改,而是通过存款、取…...

深度与视差的关系及其转换

深度与视差的关系及其转换 在计算机视觉和立体视觉中&#xff0c;深度和视差是两个重要的概念。理解这两者之间的关系对于实现立体图像处理、三维重建以及深度估计至关重要。在这篇博客中&#xff0c;我们将深入探讨深度和视差的概念&#xff0c;并介绍它们之间的转换关系。 …...

安全见闻全解析

跟随 泷羽sec团队学习 声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及…...

搭建Tomcat(四)---Servlet容器

目录 引入 Servlet容器 一、优化MyTomcat ①先将MyTomcat的main函数搬过来&#xff1a; ②将getClass()函数搬过来 ③创建容器 ④连接ServletConfigMapping和MyTomcat 连接&#xff1a; ⑤完整的ServletConfigMapping和MyTomcat方法&#xff1a; a.ServletConfigMappin…...

PT2044A 单触控单输出IC

1 产品概述 ● PT2044A 是一款单通道触摸检测芯片。该芯片内建稳压电路&#xff0c;提供稳定电压给触摸感应电路使用。同时内部集成高效完善的触摸检测算法&#xff0c;使得芯片具有稳定的触摸检测效果。该芯片专为取代传统按键而设计&#xff0c;具有宽工作电压与低功耗的特性…...

docker安装mysql5.7

1、宿主机创建映射目录 mkdir -p /data/mysql/log mkdir -p /data/mysql/data mkdir -p /data/mysql/conf这里我放在了/data/mysql目录下 2、拉取mysql镜像 docker pull mysql:5.7注意是5.7版本&#xff0c;如果是8版本操作会略有不同&#xff0c;下篇文章介绍安装8版本的操…...

安卓 文件管理相关功能记录

文件管理细分为图片、视频、音乐、文件四类 目录 权限 静态声明权限 动态检查和声明权限方法 如何开始上述动态申请的流程 提示 图片 获取图片文件的对象列表 展示 删除 视频 获取视频文件的对象列表 获取视频file列表 按日期装载视频文件列表 展示 播放 删除…...

GB28181系列三:GB28181流媒体服务器ZLMediaKit

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、ZLMediaKit介绍 二、 ZLMediaKit安装、运行(Ubuntu) 1、安装 2、运行 3、配置 三、ZLMediaKit使用 一、ZLMediaKit介绍 ZLMediaKit是一个基于C11的高性能运营级流媒体服务框架&#xff0c;项目地址&#xf…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...