Spring安全配置 - HttpSecurity与WebSecurity的区别

88

我只需要在Spring安全配置中理解一些东西。使用以下示例...

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic()
            .and()
            .authorizeRequests().antMatchers("/secret/**").authenticated()
            .and()
            .authorizeRequests().antMatchers("/**").permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

}

configure(WebSecurity web) 方法的目的是什么?

我能否在 configure(HttpSecurity http) 方法中添加 /resources/**,就像这行代码 .authorizeRequests().antMatchers("/**", "/resources/**").permitAll(); 一样。这样做不应该也可以实现允许所有请求到 /resources/** 而无需进行身份验证吗?

4个回答

100

通用的WebSecurity使用ignoring()方法忽略Spring Security,这样就无法使用Spring Security的任何功能。 WebSecurity是基于HttpSecurity之上的。

@Override
public void configure(WebSecurity web) throws Exception {
    web
        .ignoring()
        .antMatchers("/resources/**")
        .antMatchers("/publics/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .antMatchers("/publics/**").hasRole("USER") // no effect
        .anyRequest().authenticated();
}

在上面的示例中,WebSecurity 允许 Spring 忽略 /resources/**/publics/**。因此,HttpSecurity 中的 .antMatchers("/publics/**").hasRole("USER") 被忽略。

这将完全省略安全过滤器链中的请求模式。请注意,与此路径匹配的任何内容都不会应用身份验证或授权服务,并且可以自由访问。

configure(HttpSecurity) 允许基于选择匹配对基于 Web 的安全性进行资源级别的配置 - 例如,下面的示例将以 /admin/ 开头的 URL 限制为具有 ADMIN 角色 的用户,并声明任何其他 URL 需要成功验证。

configure(WebSecurity) 用于影响全局安全性的配置设置(忽略资源、设置调试模式、通过实现自定义防火墙定义拒绝请求)。例如,以下方法将导致任何以 /resources/ 开头的请求在身份验证方面被忽略


让我们考虑下面的代码,我们可以使用两种方法忽略 antMatchers 中提供的端点的身份验证。

@Override
public void configure(WebSecurity web) throws Exception {
    web
        .ignoring()
        .antMatchers("/login", "/register", "/api/public/**");
}

@Override
public void configure(HttpSecurity http) throws Exception {

    http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/login", "/register", "/api/public/**").permitAll()
        .anyRequest().authenticated();
}
  • configure(WebSecurity web) 这个方法使用的Endpoint会忽略Spring Security过滤器,安全特性(安全头部,CSRF保护等)也会被忽略,并且不会设置安全上下文,无法保护端点免受跨站脚本攻击、XSS攻击和内容嗅探。

  • configure(HttpSecurity http) 此方法使用的Endpoint会忽略antMatchers中使用的端点的身份验证,其他安全特性将生效,如安全头部,CSRF保护等。


2
在您的第二个示例中,configure(HttpSecurity http)是否完全被忽略了,因为configure(WebSecurity web)已经指定所有相同的端点应该被忽略了? - Robert Mark Bram
1
嗨 @RobertMarkBram 在configure(WebSecurity web)中声明的端点将完全被忽略,但像禁用csrf和检查除 "/login", "/register", "/api/public/**"之外的所有其他请求的其他配置仍然有效。 - Ubaid ur Rehman
HttpSecurity是否仅用于创建链并配置过滤器链?每个新的过滤器链都是一个新的HttpSecurity对象吗?它是如何工作的? - Santa Monica

23
当您使用HttpSecurity并尝试permitAll()请求时,您的请求将被允许从Spring Security过滤器链中访问。这很耗费资源,因为还有其他请求需要进入该过滤器链,并根据身份验证/授权进行允许或拒绝访问。
HttpSecurity.authorizeRequests().antMatchers("/**", "/resources/**").permitAll();

但是,当您使用时,任何对 resources 的请求都将完全绕过Spring Security过滤器链。这是安全的,因为您无需进行任何身份验证/授权即可查看图像或读取JavaScript文件。

WebSecurity.ignoring().antMatchers("/resources/**");

10
我希望通过加入一些代码来为伟大的答案做出贡献。在Spring Security中,有三个非常重要的Bean,它们是DelegatingFilterProxyFilterChainProxySecurityFilterChain。根据它们的类型,DelegatingFilterProxy将过滤请求的工作委派给一个名为springSecurityFilterChainFilterChainProxy Bean,并且FilterChainProxy的配置如下:
@Bean(
    name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
    boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
    if (!hasConfigurers) {
        WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
        });
        this.webSecurity.apply(adapter);
    }

    return (Filter)this.webSecurity.build();
}

springSecurityFilterChain(或FilterChainProxy)本身有一个SecurityFilterChain列表。 SecurityFilterChain 本身有一个实现实际逻辑的Filter实例列表。

每次我们扩展WebSecurityConfigurerAdapter并重写configure(HttpSecurity httpSecurity)方法时,实际上创建了一个SecurityFilterChain,该链将被springSecurityFilterChain使用。

springSecurityFilterChain如何从列表中选择适当的SecurityFilterChain? 基于在SecurityFilterChain接口中定义的boolean matches(HttpServletRequest request)方法。

因此,HttpSecurity用于创建自定义的SecurityFilterChain

那么WebSecurity实际上是什么时候发挥作用的呢? WebSecurity实际上允许我们自定义springSecurityFilterChain(或FilterChainProxy)。看一下如何创建springSecurityFilterChain

创建springSecurityFilterChain bean 调用的是WebSecurityperformBuild方法。

@Override
protected Filter performBuild() throws Exception {
    Assert.state(
            !securityFilterChainBuilders.isEmpty(),
            () -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
                    + "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
                    + "More advanced users can invoke "
                    + WebSecurity.class.getSimpleName()
                    + ".addSecurityFilterChainBuilder directly");
    int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
    List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
            chainSize);
    for (RequestMatcher ignoredRequest : ignoredRequests) {
        securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
    }
    for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
        securityFilterChains.add(securityFilterChainBuilder.build());
    }
    FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
    if (httpFirewall != null) {
        filterChainProxy.setFirewall(httpFirewall);
    }
    filterChainProxy.afterPropertiesSet();

    Filter result = filterChainProxy;
    if (debugEnabled) {
        logger.warn("\n\n"
                + "********************************************************************\n"
                + "**********        Security debugging is enabled.       *************\n"
                + "**********    This may include sensitive information.  *************\n"
                + "**********      Do not use in a production system!     *************\n"
                + "********************************************************************\n\n");
        result = new DebugFilter(filterChainProxy);
    }
    postBuildAction.run();
    return result;
}

正如您所看到的,当Spring想要将SecurityFilterChain注册到每个web.ignoring()....springSecurityFilterChain bean中时,Spring会将一个DefaultSecurityFilterChain添加到列表开头,而这个DefaultSecurityFilterChainSecurityFilterChain的自定义实现。
当请求到来时,springSecurityFilterChain将按顺序检查其SecurityFilterChain列表,以委托过滤工作给该SecurityFilterChainspringSecurityFilterChain将调用每个SecurityFilterChainmatch方法。如果请求URL以"/resources/**"开头,则在列表开头添加的自定义SecurityFilterChain和我们定制的SecurityFilterChain实例将负责过滤请求。
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
    securityFilterChains.add(securityFilterChainBuilder.build());
}

完全被忽略。


1
这是一个非常有教育意义的回答。谢谢@hatef-alipoor。 - NealeU

2

configure(HttpSecurity):它允许为特定的http请求配置基于web的安全性。它用于在资源级别上配置基于Web的安全性,基于选择匹配。

configure(WebSecurity):允许添加RequestMatcher实例,Spring Security应该忽略它们。


注:Original Answer 翻译成“最初的回答”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接