五SpringSecurity重要配置类--1SecurityFilterChain

五 SpringSecurity重要配置类--1SecurityFilterChain

SecurityFilterChain作用其实跟Servlet的FilterChain一样,同样维护了很多Filters,这些Filters 是由Spring Security提供的,每个 Security Filter 都有不同的职能,比如登录认证、CSRF防御...如下图所示:

image-20230816011310363

同时,Spring Security 支持添加多个SecurityFilterChain,每个SecurityFilterChain负责不同的请求(比如依据请求地址进行区分),这样可以为不同的请求设置不同的认证规则。其源码如下所示:

public interface SecurityFilterChain {
    // 匹配请求
    boolean matches(HttpServletRequest request);
    // 获取该 SecurityFilterChain 中的所有 Filter
    List<Filter> getFilters();
}

具体来说,当请求到达FilterChainProxy时,其内部会根据当前请求匹配得到对应的SecurityFilterChain,然后将请求依次转发给到该SecurityFilterChain中的所有 Security Filters。如下图所示:

image-20230816011436124

4.3.0 DefaultSecurityFilterChain(过滤器链唯一实现)

SecurityFilterChain 接口只有一个实现类,那就是 DefaultSecurityFilterChain:

public final class DefaultSecurityFilterChain implements SecurityFilterChain {
	private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class);
	private final RequestMatcher requestMatcher;
	private final List<Filter> filters; //当前chain上对应的filters

	public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
		this(requestMatcher, Arrays.asList(filters));
	}

	public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
		logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
		this.requestMatcher = requestMatcher;
		this.filters = new ArrayList<>(filters);
	}

	public RequestMatcher getRequestMatcher() {
		return requestMatcher;
	}

	public List<Filter> getFilters() {
		return filters;
	}

	public boolean matches(HttpServletRequest request) {
		return requestMatcher.matches(request);
	}

	@Override
	public String toString() {
		return "[ " + requestMatcher + ", " + filters + "]";
	}
}

DefaultSecurityFilterChain 只是对 SecurityFilterChain 中的方法进行了实现,并没有特别值得说的地方,松哥也就不啰嗦了。

那么从上面的介绍中,DefaultSecurityFilterChain 其实就相当于是 Spring Security 中的过滤器链,一个 DefaultSecurityFilterChain 代表一个过滤器链,如果系统中存在多个过滤器链,则会存在多个 DefaultSecurityFilterChain 对象

4.3.1 多个过滤器链的配置

在前面讲述和实例中,过滤器链配置如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin/**").hasRole("admin")
            .antMatchers("/user/**").hasRole("user")
            .anyRequest().authenticated()
            ...
            .csrf().disable();
}

这是一个过滤器链。因为不管是 /admin/** 还是 /user/** ,走过的过滤器都是一样的,只是不同的路径判断条件不一样而已。

如果系统需要配置多个过滤器链,需要在 FilterChainProxy按照下图进行划分的情况:

image-20230822033636976

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

多个过滤器链的配置如下:

@Configuration
public class SecurityConfig {
    @Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("javaboy").password("{bcrypt}$2a$10$Sb1gAUH4wwazfNiqflKZve4Ubh.spJcxgHG8Cp29DeGya5zsHENqi").roles("admin", "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 中的过滤器链,至于是怎么配置的,详见随后章节。

总结:

首先,http.authorizeRequests() 配置并非总在第一行出现,如果只有一个过滤器链,他总是在第一行出现,表示该过滤器链的拦截规则是 /**请求只有先被过滤器链拦截下来,接下来才会进入到不同的 Security Filters 中进行处理),如果存在多个过滤器链,就不一定了。

仅仅从字面意思来理解,authorizeRequests() 方法的返回值是 ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry,ExpressionUrlAuthorizationConfigurer 可以为多组不同的 RequestMatcher 配置不同的权限规则,就是大家看到的 .antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").hasRole("user")

4.3.2 spring security执行机制

image-20230816012002824

Spring Security 作用机制大致如下:

  1. 注册标准Filter:首先,Spring 会自动注入一个DelegatingFilterProxy到 Servlet 的FilterChain中
  2. 请求转发到 Spring Security:当请求到来时,DelegatingFilterProxy就会自动在 Spring容器 中搜索名称为springSecurityFilterChain的Filter实体,其实际类型为FilterChainProxy。DelegatingFilterProxy最终会将请求转发给到FilterChainProxy。
  3. 找到匹配请求处理的SecurityFilterChain:FilterChainProxy内部维护了一系列SecurityFilterChains,他会依据请求内容找到对应处理该请求的SecurityFilterChain。
  4. 请求处理:找到能处理请求的第一个SecurityFilterChain后,就会遍历该SecurityFilterChain内部维护的一系列Filters,依次让这些 Security Filter 处理该请求,完成认证、授权等功能。
posted @ 2023-08-28 22:58  LeasonXue  阅读(1632)  评论(0编辑  收藏  举报