Spring Безопасность исключает шаблоны URL-адресов в конфигурации аннотации безопасности

У меня есть spring веб-приложение с spring безопасностью, настроенной с использованием java config-подхода. Я хочу исключить некоторые шаблоны URL из проверки подлинности (например: статические ресурсы и т.д.). Я сделал это раньше с spring конфигурацией безопасности xml, но не смог понять с помощью java config, поскольку добавление 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, которую я использую, - 3.2.0. Заранее благодарим за помощь

Edit:

Стек, которую я получил при удалении исключенного 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, в то время как он не должен, поскольку запрос игнорируется с помощью antmatcher

Ответ 1

Нашел решение в Spring примерах безопасности, опубликованных в Github.

WebSecurityConfigurerAdapter имеет перегруженное сообщение configure, которое принимает WebSecurity как аргумент, который принимает ant совпадения в запросах, которые нужно игнорировать.

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

Подробнее см. Spring Образцы безопасности

Ответ 2

Где вы настраиваете свой шаблон с проверкой подлинности? Я вижу только один uri в вашем коде.

У вас есть несколько методов настройки (HttpSecurity) или только один? Похоже, что вам нужны все ваши URI в одном методе.

У меня есть сайт, который требует аутентификации для доступа ко всем, поэтому я хочу защитить /*. Однако для аутентификации я, очевидно, не хочу защищать/входить в систему. У меня также есть статические ресурсы, которые я хотел бы разрешить для доступа (так что я могу сделать страницу входа довольно красивой) и страницу healthcheck, которая не требует авторизации.

Кроме того, у меня есть ресурс /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. Аналогично, у меня был /admin/ ** last:

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

Это привело к тому, что мой непринужденный пользователь теста "гость" имел доступ к интерфейсу администратора (yikes!)

Ответ 3

Когда вы говорите, что добавление antMatchers не помогает - что вы имеете в виду? antMatchers - это именно то, как вы это делаете. Что-то вроде следующего должно работать (явно изменяя ваш URL-адрес):

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

Если у вас все еще нет радости, вам нужно будет предоставить более подробную информацию /stacktrace и т.д.

Подробности конфигуратора конфигурации XML для Java здесь