Как добавить несколько пользовательских фильтров в Spring Security 3?
Мне нужно добавить два настраиваемых фильтра для FORM_LOGIN_FILTER, например.
<custom-filter after="FORM_LOGIN_FILTER" ref="myUsernamePasswordAuthenticationFilter" />
<custom-filter after="FORM_LOGIN_FILTER" ref="myUsernamePasswordAuthenticationFilter2" />
Я ожидаю, что последовательность фильтров:
1. Predefind FORM_LOGIN_FILTER
2. myUsernamePasswordAuthenticationFilter
3. myUsernamePasswordAuthenticationFilter2
Но выше приведет к ошибке конфигурации.
Итак, кто-нибудь знает, как написать правильный конфиг?
Спасибо!
Ответы
Ответ 1
Сделайте это:
<custom-filter after="FORM_LOGIN_FILTER" ref="myUsernamePasswordAuthenticationFilter" />
<custom-filter before="BASIC_AUTH_FILTER" ref="myUsernamePasswordAuthenticationFilter2" />
Это должно помещать их туда, где вы хотите.
Ответ 2
Используйте Spring CompositeFilter
, чтобы упаковать список настраиваемых фильтров, а затем поместите этот фильтр в соответствующее положение на SecurityFilterChain
.
например. например:
<bean id="customFilters" class="org.springframework.web.filter.CompositeFilter">
<property name="filters">
<list>
<ref bean="myUsernamePasswordAuthenticationFilter"/>
<ref bean="myUsernamePasswordAuthenticationFilter2"/>
</list>
</property>
</bean>
...
<custom-filter after="FORM_LOGIN_FILTER" ref="customFilters" />
Ответ 3
Я решил это так:
public class QmLoginFilterWrapper extends GenericFilterBean implements ApplicationEventPublisherAware,
MessageSourceAware
{
private static final Logger LOGGER = LoggerFactory.getLogger(QmLoginFilterWrapper.class);
private List<AbstractAuthenticationProcessingFilter> filterList = new ArrayList<AbstractAuthenticationProcessingFilter>();
@Override
public void doFilter(ServletRequest request, ServletResponse response, final FilterChain chain) throws IOException,
ServletException
{
FilterChain filterChain = new FilterChain() {
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException
{
chain.doFilter(arg0, arg1);
}
};
Vector<FilterChain> filterChains = new Vector<FilterChain>();
filterChains.add(filterChain);
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Filtering {} filters", filterList.size());
}
for (final GenericFilterBean filter : filterList)
{
final FilterChain lastChain = filterChains.lastElement();
FilterChain loopChain = new FilterChain() {
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1) throws IOException, ServletException
{
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("running filter {}", filter.getClass().getName());
}
filter.doFilter(arg0, arg1, lastChain);
}
};
filterChains.add(loopChain);
}
filterChains.lastElement().doFilter(request, response);
}
@Override
public void setMessageSource(MessageSource messageSource)
{
for (MessageSourceAware filter : filterList)
{
filter.setMessageSource(messageSource);
}
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
{
for (ApplicationEventPublisherAware applicationEventPublisherAware : filterList)
{
applicationEventPublisherAware.setApplicationEventPublisher(applicationEventPublisher);
}
}
public List<AbstractAuthenticationProcessingFilter> getFilterList()
{
return filterList;
}
public void setFilterList(List<AbstractAuthenticationProcessingFilter> filterList)
{
this.filterList = filterList;
Collections.reverse(this.filterList);
}
}
Тогда в контексте XML у меня есть:
<bean id="qmAuthFilter" class="com.qmplus.common.logon.QmLoginFilterWrapper">
<property name="filterList">
<list>
<ref local="samlProcessingFilter" />
<ref local="usernamePasswordAuthenticationFilter" />
</list>
</property>
</bean>