Spring Security 在安全注释配置中排除 url 模式

问题描述 投票:0回答:8

我有一个 Spring Web 应用程序,使用 java 配置方法配置了 Spring security。我想从身份验证中排除一些 URL 模式(例如:静态资源等..)。我之前已经使用 spring security xml 配置完成了此操作,但无法使用 java 配置来弄清楚,因为添加 antmatchers 没有帮助。以下是我在安全配置类中添加的代码,扩展了

WebSecurityConfigurerAdapter

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/authFailure")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .and()
                .authenticationProvider(_provider)
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilter(authFilter())
                .addFilterAfter(executionContextFilter(),
                        TokenBasedSecurityFilter.class).csrf().disable();
    }

我使用的Spring Security版本是3.2.0。

编辑:

我在点击排除的 URL 时获得的堆栈跟踪,

org.springframework.security.authentication.AuthenticationServiceException: Authorization Header is not available in the request
    at com.inventory.ricemill.tba.spring.TokenBasedSecurityFilter.doFilter(TokenBasedSecurityFilter.java:59)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

Apr 01, 2014 10:18:41 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Inventory] in context with path [/ricemill] threw exception [Request processing failed; nested exception is org.springframework.security.authentication.AuthenticationServiceException: Authorization Header is not available in the request] with root cause
org.springframework.security.authentication.AuthenticationServiceException: Authorization Header is not available in the request
    at com.inventory.ricemill.tba.spring.TokenBasedSecurityFilter.doFilter(TokenBasedSecurityFilter.java:59)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)

请求通过在 Spring Security 过滤器链中注册的过滤器,但它不应该通过,因为 antmatcher 会忽略该请求

spring spring-mvc spring-security basic-authentication
8个回答
115
投票

在 Github 上发布的 Spring 安全示例中找到了解决方案。

WebSecurityConfigurerAdapter
有一个重载的
configure
消息,它以
WebSecurity
作为参数,接受要忽略的请求上的 ant 匹配器。

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

请参阅 Spring Security 示例了解更多详细信息


39
投票

您在哪里配置经过身份验证的 URL 模式?我在你的代码中只看到一个 uri。

您有多个配置(HttpSecurity)方法还是只有一个?看起来您需要在一个方法中使用所有 URI。

我有一个需要身份验证才能访问所有内容的网站,因此我想保护 /*。然而,为了进行身份验证,我显然不想保护/登录。我还希望允许访问静态资产(这样我可以使登录页面变得漂亮)和不需要身份验证的运行状况检查页面。

此外,我有一个资源 /admin,它需要比网站其他部分更高的权限。

以下对我有用。

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

    http.authorizeRequests()
        .antMatchers("/login**").permitAll()
        .antMatchers("/healthcheck**").permitAll()
        .antMatchers("/static/**").permitAll()
        .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
        .antMatchers("/**").access("hasRole('ROLE_USER')")
        .and()
            .formLogin().loginPage("/login").failureUrl("/login?error")
                .usernameParameter("username").passwordParameter("password")
        .and()
            .logout().logoutSuccessUrl("/login?logout")
        .and()
            .exceptionHandling().accessDeniedPage("/403")
        .and()
            .csrf();

}

注意:这是第一场比赛获胜,因此您可能需要按照顺序进行比赛。 例如,我最初有 /** 首先:

        .antMatchers("/**").access("hasRole('ROLE_USER')")
        .antMatchers("/login**").permitAll()
        .antMatchers("/healthcheck**").permitAll()

这导致网站不断将所有 /login 请求重定向回 /login。同样,我最后有/admin/**:

        .antMatchers("/**").access("hasRole('ROLE_USER')")
        .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")

这导致我的非特权测试用户“guest”可以访问管理界面(哎呀!)


14
投票

当您说添加 antMatchers 没有帮助时 - 您的意思是什么? antMatchers 正是您的做法。像下面这样的东西应该可以工作(显然适当地改变你的URL):

@Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/authFailure").permitAll()
                .antMatchers("/resources/**").permitAll()
                .anyRequest().authenticated()

如果您仍然没有任何乐趣,那么您将需要提供更多详细信息/堆栈跟踪等。

XML 到 Java 配置开关的详细信息在这里


10
投票

对此处已给出的答案的补充。
对于身份验证和授权之间的区别,似乎有很多混淆。

Spring Security 先执行身份验证,然后才执行授权,这是有道理的。

这意味着它将首先执行身份验证过滤器,然后才验证授权端点。

要规避自定义身份验证过滤器,

permitAll
将不起作用,因为这涉及授权,并且NOT身份验证。
Spring Security 5.7.0-M2 弃用了
WebSecurityConfigurerAdapter

可以使用以下方式忽略身份验证过滤器:

 @Bean
 public WebSecurityCustomizer ignoringCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/ignore1", "/ignore2");
 }
 

或者使用 antMatchers。


7
投票

在“authorizeRequests()”之前指定“antMatcher”,如下所示,会将身份验证限制为仅在“antMatcher”中指定的那些 URL

http.csrf().disable() .antMatcher("/apiurlneedsauth/**").authorizeRequests().


3
投票

以更现代的方式,它应该看起来像:

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().antMatchers("/authFailure");
    }


1
投票

我发现上面所有的解决方案已经过时了... 这就是我最终得到的解决方案

@Configuration
@EnableWebSecurity/*(debug = true)*/
@RequiredArgsConstructor
@EnableMethodSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    // @formatter:off
    return http
        .csrf()
            .disable()
            .headers().frameOptions().disable()
        .and()
        // Enable CORS at Spring Security level
        .cors()
        .and()
        .authorizeHttpRequests()
            .requestMatchers("/login/**", "/api/noAuth/**")
                .permitAll()
            .anyRequest()
                .authenticated()
        .and()
        .oauth2ResourceServer()
            .jwt()
                .jwtAuthenticationConverter(new CustomJwtAuthenticationConverter(new UserDetailsConverter()))
        .and()
        .and().build();
    // @formatter:on

}

}


0
投票

对于 SpringBoot 版本 6,请考虑在配置中定义一个 bean,并添加您想要忽略安全检查的 url。

@Bean
公共 WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring().requestMatchers("/yourUrlToIgnore","/secondurl"...); }

有关更多详细信息,请检查此,https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter

© www.soinside.com 2019 - 2024. All rights reserved.