栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spirng Security (八)多个过滤器链共存

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spirng Security (八)多个过滤器链共存

一项目搭建

pom.xml



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.7.1
         
    
    com.example
    twoConfig
    0.0.1-SNAPSHOT
    twoConfig
    twoConfig
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-security
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.security
            spring-security-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    



application.properties

spring.security.user.name=zhangsan
spring.security.user.password=123

HelloController

package com.qfedu.security05;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    
    @GetMapping("/phone/hello")
    public String phone() {
        return "phone";
    }

    
    @GetMapping("/web/hello")
    public String web() {
        return "web";
    }
}

SecurityConfig
依旧是最重要的配置,下面内容都围绕着这里

二.获取登录用户信息

首先,服务器一定是将用户信息存到HttpSession。
1.首先前端发起一个登录请求,这个请求会经过SpringSecurity一系列的过滤器,SecurityContextPersistenceFilter过滤器中,主要用来处理当前用户信息。当用户登录成功之后,会自动将用户信息存入到SecurityContextHolder中,SecurutyContextHolder的底层就是ThreadLocal。
2.在请求处理完毕后,响应数据给前端的时候,也会经过SecurityContextPersistenceFilter过滤器,此时,系统会自动将刚刚登录成功的用户信息存入到HttpSession中。
3.下一次请求来的时候,还是会经过SecurityContextPersistenceFilter过滤器,此时系统会自动从HttpSession中读取出当前登录成功的登录信息,并将之存入到SecurityContextyHolder。(这也就说明了只有是同一个线程中的信息才能够被获取到)

三.多个过滤器链共存

知识积累:

之前我们提到过Spring Security 中一共提供了 32 个过滤器,其中默认使用的有 15 个,个 Web 项目中,请求流程大概如下图所示:

请求从客户端发起(例如浏览器),然后穿过层层 Filter,最终来到 Servlet 上,被 Servlet 所处理。
,那么Spring Security 中默认的 15 个过滤器就是这样嵌套在 Client 和 Servlet 之间吗?
不是的!上图中的 Filter 我们可以称之为 Web Filter,Spring Security 中的 Filter 我们可以称之为 Security
Filter,它们之间的关系如下图:

Spring Security Filter 并不是直接嵌入到 Web Filter 中的,而是通过 FilterChainProxy 来统
一管理 Spring Security Filter,FilterChainProxy 本身则通过 Spring 提供的 DelegatingFilterProxy 代
理过滤器(就是我们SecurityConfig中配置的代理过滤器)嵌入到 Web Filter 之中
。
扩展:DelegatingFilterProxy 很多小伙伴应该比较熟悉,在 Spring 中手工整合 Spring Session、Shiro
等工具时都离不开它,现在用了 Spring Boot,很多事情 Spring Boot 帮我们做了,所以有时候会
感觉 DelegatingFilterProxy 的存在感有所降低,实际上它一直都在。

2.1 错误的多条过滤器链处理方式


注意:过滤器链,不是两条顾虑器链,这么写仍旧是一条过滤器链,走过的过滤器都是一样的,只是不同的路径判断条件不一样而已

2.2正确的多条过滤器链的处理方式(项目配置的例子)

可以看到,当请求到达 FilterChainProxy 之后,FilterChainProxy 会根据请求的路径,将请求转发到不同的 Spring Security Filters 上面去,不同的 Spring Security Filters 对应了不同的过滤器,也就是不同的请求将经过不同的过滤器。

securtyConfig

package com.twoconfig.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {

    UserDetailsService us1() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("lisi").password("{noop}123").roles("admin").build());
        return manager;
    }

    UserDetailsService us2() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("wangwu").password("{noop}123").roles("admin").build());
        return manager;
    }

    
    @Bean
    SecurityFilterChain securityFilterChain01(HttpSecurity http) throws Exception {
        http.antMatcher("/phone
    @Bean
    SecurityFilterChain securityFilterChain02(HttpSecurity http) throws Exception {
        http.antMatcher("/web/**")
                .userDetailsService(us2())
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/web/login")
                .loginProcessingUrl("/web/login")
                .successHandler((req,resp,auth)->{
                    resp.getWriter().write("web login success");
                })
                .and()
                .sessionManagement()
                .maximumSessions(1)
                .maxSessionsPreventsLogin(true)
                .and().and()
                .csrf().disable();
        return http.build();
    }


}

测试结果phone

测试结果web

2.3引用江南大佬的例子
	@Configuration
 public class SecurityConfig 
 {

	@Bean 
	protected UserDetailsService userDetailsService() {
	InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); 
	manager.createUser(User.withUsername("javaboy")
	.password(" {bcrypt}$2a$10$Sb1gAUH4wwazfNiqflKZve4Ubh
	.spJcxgHG8Cp29DeGya5zsHENqi")
	.roles("ad min", "aaa", "bbb").build()); 
	
	manager.createUser(User.withUsername("sang")
	.password(" {noop}123")
	.roles("admin").build()); 
	manager.createUser(User.withUsername("江南一点雨")
	.password("{MD5} {Wucj/L8wMTMzFi3oBKWsETNeXbMFaHZW9vCK9mahMHc=}4d43db282b36d7f0421498fdc693f2a2") 
	.roles("user", "aaa", "bbb").build()); 
	return manager; }
	
	
	
	@Configuration
	@Order(1) 
	static class DefaultWebSecurityConfig extends WebSecurityConfigurerAdapter 
	{ @Override protected void configure(HttpSecurity http) throws Exception 
	{ http.antMatcher("/foo/**") 
	.authorizeRequests() 
	.anyRequest()
	.hasRole("admin")
	.and() 
	.csrf()
	.disable()
	; 
	}
	}
	
	
	
	@Configuration 
	@Order(2) 
	static class DefaultWebSecurityConfig2 extends WebSecurityConfigurerAdapter { 
	@Override 
	protected void configure(HttpSecurity http) throws Exception {
	http.antMatcher("/bar/**") 
	.authorizeRequests() 
	.anyRequest()
	.hasRole("user") 
	.and() 
	.formLogin() 
	.permitAll() 
	.and() 
	.csrf()
	.disable(); 
	} 
	} 
	}
  1. 首先,SecurityConfig 不再需要继承自 WebSecurityConfigurerAdapter 了,只是作为一个普通的
    配置类,加上 @Configuration 注解即可。
  2. 提供 UserDetailsService 实例,相当于是我们的数据源。
  3. 创建静态内部类继承 WebSecurityConfigurerAdapter 类,同时用 @Configuration 注解标记静态
    内部类是一个配置类,配置类里边的代码就和之前的一样了,无需赘述。
  4. 每一个静态内部类相当于就是一个过滤器链的配置。
  5. 注意在静态内部类里边,我没有使用 http.authorizeRequests() 开始,
    http.authorizeRequests() 配置表示该过滤器链过滤的路径是 /** 。在静态内部类里边,我
    是用了 http.antMatcher("/bar/") 开启配置,表示将当前过滤器链的拦截范围限定在
    /bar/ 。
  6. 当存在多个过滤器链的时候,必然会有一个优先级的问题,所以每一个过滤器链的配置类上通过
    @Order(2) 注解来标记优先级。
    从上面这段代码中大家可以看到,configure(HttpSecurity http) 方法似乎就是在配置过滤器链?是的没错!我们在该方法中的配置,都是在添加/移除/修改 Spring Security 默认提供的过滤器,所以该方法就
    是在配置 Spring Security 中的过滤器链
    Spring Security 竟然可以同时存在多个过滤器链-江南一点雨
    FilterChainProxy 是怎么处理多条过滤器链
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020450.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号