Spring Security(学习笔记) --AuthenticationProvider案例演示梳理!

server/2024/11/13 5:32:31/

重点标识

AuthenticationManager 默认是有parent的。
Security 向Spring容器注册了一个AuthenticationManager ,是一个全局的,也就是所谓的parent。

注册一个AuthenticationManager ,就是一个全局的
如果想要局部的,可以设置一个过滤器链。

我们平时配置的,都是局部的。

正常来说,请求到达的时候,都是局部的AuthenticationManager 来处理的,没配置,系统会自动配置。

如果这个AuthenticationManager 处理不了当前的认证,就会交给parent来处理。也就是所谓的全局的AuthenticationManager 。

代码演示

我们来看一下,自己配置两个局部过滤器链,然后分别登录,能不能达到我们想要的效果。


@Configuration
public class SecurityConfig {/**** 全局的AuthenticationManager 的用户就是这样配* @return*/@BeanUserDetailsService globalUser(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("global").password("{noop}123").build());return inMemoryUserDetailsManager;}UserDetailsService adminUser(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("{noop}123").build());return inMemoryUserDetailsManager;}UserDetailsService rootUser(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").build());return inMemoryUserDetailsManager;}@Bean@Order(2)SecurityFilterChain securityRootFilterChain(HttpSecurity http) throws Exception {http//这里就是我们一开始说的,Security可以提供多个过滤器链,可以在这里进行分流,针对不同的情况,走不同的过滤器.securityMatcher("/root/**").authorizeHttpRequests(a->a.anyRequest().authenticated())//这里注意,由于过滤器链中存在AuthenticationManager 因此可以直接将数据源加载到过滤器链中.userDetailsService(rootUser()).formLogin(f ->f.loginProcessingUrl("/root/login").successHandler(((request, response, authentication) -> {response.getWriter().write(authentication.getName());})).permitAll()).csrf(c -> c.disable());return http.build();}@Bean@Order(1)SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.securityMatcher("/admin/**").authorizeHttpRequests(a->a.anyRequest().authenticated()).userDetailsService(adminUser()).formLogin(f ->f.loginProcessingUrl("/admin/login").successHandler(((request, response, authentication) -> {response.getWriter().write(authentication.getName());})).permitAll())//.csrf(c -> c.disable());return http.build();}
}

使用postMan测一下,全局的,没问题
在这里插入图片描述
root地址下的,也没问题。
在这里插入图片描述
但是,如果我们在root地址下,使用admin登录,那就有问题了。
在这里插入图片描述
但是,如果我们在admin地址下,登录admin,自然是没问题的
在这里插入图片描述
这就达成了我们想要的结果,两个局部的过滤器链,彻底分开,各自走各自的,同时,全局的过滤器链,两个都可以访问。

也验证了我们上一篇所了解的,AutehnticationManager中,如果找不到,就会去寻找它的父类里面的Provider了。

同时,我们可以看一下这部分源码,过滤器链都是通过HttpSecurity构建的,那我们可以想一下,HttpSecurity肯定不会是一个单例,不然写在多都会被覆盖,都是同一个。

进入到HttpSecurityConfiguration中,看一下,果然如此,prototype,可以有多个httpSecurity。在这里插入图片描述
OK,我们再看一下这部分源码
AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(this.objectPostProcessor, passwordEncoder);
建造者模式,构建了一个authenticationBuilder ,然后我们接着往下看。authenticationBuilder.parentAuthenticationManager(this.authenticationManager());
设置parent,这个parent就是 从Spring容器中拿的。

private AuthenticationManager authenticationManager() throws Exception {return this.authenticationConfiguration.getAuthenticationManager();}public AuthenticationManager getAuthenticationManager() throws Exception {if (this.authenticationManagerInitialized) {return this.authenticationManager;} else {AuthenticationManagerBuilder authBuilder = (AuthenticationManagerBuilder)this.applicationContext.getBean(AuthenticationManagerBuilder.class);if (this.buildingAuthenticationManager.getAndSet(true)) {return new AuthenticationManagerDelegator(authBuilder);} else {Iterator var2 = this.globalAuthConfigurers.iterator();while(var2.hasNext()) {GlobalAuthenticationConfigurerAdapter config = (GlobalAuthenticationConfigurerAdapter)var2.next();authBuilder.apply(config);}this.authenticationManager = (AuthenticationManager)authBuilder.build();if (this.authenticationManager == null) {this.authenticationManager = this.getAuthenticationManagerBean();}this.authenticationManagerInitialized = true;return this.authenticationManager;}}}

那它怎么保证Spring容器中一定存在AuthenticationManager呢,就是上面这部分,就是下面这部分代码,Bean,往Spring容器中注册。

@Beanpublic AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);AuthenticationEventPublisher authenticationEventPublisher = this.getAuthenticationEventPublisher(context);DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);if (authenticationEventPublisher != null) {result.authenticationEventPublisher(authenticationEventPublisher);}return result;}

上面这部分是基于Security提供的provider来实现的,我们来看自己配置的。

区别不是很大,有兴趣的,可以对照上面的进行测一下,效果是一样的。


@Configuration
public class SecurityConfig {/**** 全局的AuthenticationManager 的用户就是这样配* @return*/UserDetailsService globalUser(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("global").password("{noop}123").build());return inMemoryUserDetailsManager;}UserDetailsService adminUser(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("admin").password("{noop}123").build());return inMemoryUserDetailsManager;}AuthenticationManager adminAuthenticationManager(){DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(adminUser());ProviderManager providerManager = new ProviderManager(Arrays.asList(daoAuthenticationProvider),globalAuthenticationManager());return providerManager;}private AuthenticationManager globalAuthenticationManager() {DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(globalUser());ProviderManager providerManager = new ProviderManager(Arrays.asList(daoAuthenticationProvider));return providerManager;}AuthenticationManager rootAuthenticationManager(){DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService(rootUser());ProviderManager providerManager = new ProviderManager(Arrays.asList(daoAuthenticationProvider),globalAuthenticationManager());return providerManager;}UserDetailsService rootUser(){InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").build());return inMemoryUserDetailsManager;}@Bean@Order(2)SecurityFilterChain securityRootFilterChain(HttpSecurity http) throws Exception {http//这里就是我们一开始说的,Security可以提供多个过滤器链,可以在这里进行分流,针对不同的情况,走不同的过滤器.securityMatcher("/root/**").authorizeHttpRequests(a->a.anyRequest().authenticated())//这里注意,由于过滤器链中存在AuthenticationManager 因此可以直接将数据源加载到过滤器链中// .userDetailsService(rootUser()).authenticationManager(rootAuthenticationManager()).formLogin(f ->f.loginProcessingUrl("/root/login").successHandler(((request, response, authentication) -> {response.getWriter().write(authentication.getName());})).permitAll()).csrf(c -> c.disable());return http.build();}@Bean@Order(1)SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.securityMatcher("/admin/**").authorizeHttpRequests(a->a.anyRequest().authenticated()).authenticationManager(adminAuthenticationManager())// .userDetailsService(adminUser()).formLogin(f ->f.loginProcessingUrl("/admin/login").successHandler(((request, response, authentication) -> {response.getWriter().write(authentication.getName());})).permitAll())//.csrf(c -> c.disable());return http.build();}
}

结语

枯燥,但是有用!


http://www.ppmy.cn/server/20940.html

相关文章

什么是SSRF攻击?该如何防御SSRF攻击?

随着网络安全形式日益严峻&#xff0c;各式各样的攻击频繁发生。当前&#xff0c;应用程序为了给用户提供更多更方便的功能&#xff0c;从另一个URL获取数据的场景越来越多&#xff0c;因此出现了一种安全漏洞攻击-SSRF。并且&#xff0c;由于云服务和体系结构的复杂性&#xf…

分发糖果——使用贪心算法

135. 分发糖果 已解答 困难 相关标签 相关企业 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给…

2024LarkXR新增功能系列之二 | 普通应用多开推流

在数字化迅速演变的今天&#xff0c;3D数字时代的到来已经改变了许多行业的运作方式。特别是在虚拟现实领域&#xff0c;实时云渲染技术正迅速成为关键驱动力&#xff0c;这种技术使得复杂的3D视觉内容可以迅速、高效地通过云平台渲染并传输到用户的设备上&#xff0c;无论设备…

opencv绘制线段------c++

绘制线段 bool opencvTool::drawLines(std::string image_p, std::vector<cv::Point> points) {cv::Mat ima cv::imread(image_p.c_str()); // 读取图像&#xff0c;替换为你的图片路径 cv::Scalar red cv::Scalar(0, 0, 255); // Red color int thickness 2;// 遍…

R语言高级数据管理

一&#xff0c;数学函数 绝对值函数abs(x) sqrt(x) 开平方根 不小于某个数的最小整数ceiling(x) 不大于某个数的最大整数floor(x) 四舍五入round(x) sin(x) cos(x) log(x) 二&#xff0c;统计函数 求平均值 > x<-c(2,3,4,5,6,7,8,9,10) > mean(x) 求和 &g…

未来已来:解锁AGI的无限潜能与挑战

未来已来&#xff1a;解锁AGI的无限潜能与挑战 引言 假设你有一天醒来&#xff0c;发现你的智能手机不仅提醒你今天的日程&#xff0c;还把你昨晚做的那个奇怪的梦解释了一番&#xff0c;并建议你可能需要减少咖啡摄入量——这不是科幻电影的情节&#xff0c;而是人工通用智能…

Scala Extention

正则 import scala.util.matching.Regex import scala.util.matching.Regex.Match/*----------------------------------------------------------匹配 */ val rtr "^(\\w)([a-z0-9]{2,})\\.(com|cn|edu|org)$"; val regex:Regex rtr.r // 同 Java 的简单匹配 val…

【LeetCode刷题记录】94. 二叉树的中序遍历

94 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[] 示例 3&#xff1a; 输入&…