Добавление настраиваемого фильтра, который будет вызываться после фильтра Spring-Security в среде Servlet 3+
Я использую Spring-Security 3.2.4 и Spring Boot 1.1.0 (и связанные с ним версии 4.X). Я пишу веб-приложение, которое будет работать во встроенном коте.
Я пытаюсь добавить два дополнительных фильтра (не связанных с безопасностью Spring), один из которых будет вызван до Spring-Security-FilterChainProxy, а другой будет вызван после Spring-Security-FilterChainProxy.
Мои файлы конфигурации Spring-Security:
@Configuration
@EnableWebMvcSecurity
public class SecurityCtxConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("pass").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.usernameParameter("user").passwordParameter("password");
}
}
И Основной класс (Application.class):
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
@Bean
RequestFilter beforeSpringSecurityFilter(){
return new RequestFilter();
}
@Bean
RequestFilter afterSpringSecurityFilter(){
return new RequestFilter();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
И реализация фильтра:
public class RequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
Есть ли способ управления порядком вызова, если принять во внимание FilterChainProxy (который создается WebSecurityConfigurerAdapter? Чтобы быть точным, требуется следующий порядок:
- запрос-фильтр-1
- Spring-Security FilterChain
- запрос-фильтр-2
Спасибо
4 ответа
FilterChainProxy
использование Spring Security не Ordered
(если бы вы могли заказать все ваши фильтры). Но вы должны быть в состоянии зарегистрировать его в FilterRegistrationBean
который является Ordered
и зарегистрируйте ваши другие фильтры таким же образом. В случае фильтра безопасности вы можете ввести его по имени в компонент регистрации. Другие вы, вероятно, можете ввести, позвонив @Bean
метод.
Согласен со всем, что было сказано Дейвом Сайером;), но хотел бы добавить пример конфигурации Java с использованием FilterRegistrationBean.
В моей ситуации я обнаружил, что мой пользовательский фильтр безопасности (использующий Spring Security) запускался дважды для каждого запроса. Добавление FilterRegistrationBean
конфиг исправил это.
@Bean(name = "myFilter")
public MyAuthenticationFilter myAuthenticationFilter(final MyAuthenticationEntryPoint entryPoint) {
final MyAuthenticationFilter filter = new MyAuthenticationFilter();
filter.setEntryPoint(entryPoint);
return filter;
}
/**
* We do this to ensure our Filter is only loaded once into Application Context
*
*/
@Bean(name = "authenticationFilterRegistration")
public FilterRegistrationBean myAuthenticationFilterRegistration(final MyAuthenticationFilter filter) {
final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
(Относительно моей конкретной проблемы с фильтром, который был зарегистрирован дважды в контексте приложения - вместо того, чтобы использовать FilterRegistrationBean
Я также нашел повторную реализацию MyAuthenticationFilter
наследовать от OncePerRequestFilter
вместо GenericFilterBean
тоже сработало. Тем не мение, OncePerRequestFilter
поддержка от Servlet 3.x и выше, и поскольку я писал публичную библиотеку, поддержка Servlet 2.x может понадобиться)
В какой-то момент весенняя загрузка показала фильтр безопасности как свойство. Сейчас это сделать довольно легко.
В вашем приложении.yml:
spring:
security:
filter:
order: 20
И какой-то фильтр, который вы хотите вызвать после того, как Spring Security сделает это:
@Bean
public FilterRegistrationBean<Filter> afterAuthFilterRegistrationBean() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
//a filter that extends OncePerRequestFilter
AfterAuthFilter afterAuthFilter = new AfterAuthFilter();
registrationBean.setFilter(afterAuthFilter);
//this needs to be a number greater than than spring.security.filter.order
registrationBean.setOrder(30);
return registrationBean;
}
Для фильтра, который выполняется перед безопасностью Spring, установите порядок на число меньше 20.
Если вы используете подходы web.xml, вы можете выполнить следующие действия: /questions/25904704/kak-napisat-sobstvennyij-filtr-v-spring-security/25904716#25904716
Если вы используете подходы конфигурации Java, вы можете сделать это в WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(your-request-filter-1, ChannelProcessingFilter.class);
http.addFilterAfter(your-request-filter-2, SwitchUserFilter.class);
}
Всегда проверяйте версию библиотеки, которую вы используете, и обращайтесь к конкретному документу для правильного порядка цепочек фильтров:
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/
Или, если вы используете AbstractSecurityWebApplicationInitializer, вы можете использовать insertFilters
или же appendFilters
,
public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
}
Более подробная информация.