如何仅针对特定 url 添加 Spring Security 验证码过滤器
Posted
技术标签:
【中文标题】如何仅针对特定 url 添加 Spring Security 验证码过滤器【英文标题】:Howto additionally add Spring Security captcha filter for specific urls only 【发布时间】:2016-03-22 17:03:56 【问题描述】:我正在寻找一种非侵入性的方式来为某些 api 调用添加验证码过滤器。
我的设置包含两个WebSecurityConfigurerAdapters
,每个都有一个过滤器(不是验证码过滤器):
如何在公共、内部 api 或外部 api 调用中添加过滤器之前 Spring Security 的东西?我不需要SecurityContext,只需要检查请求标头中的验证码,转发到filterChain(普通过滤器)或手动拒绝访问。我尝试在 web.xml 中声明一个过滤器,但这破坏了使用依赖注入的能力。
这是我的 Spring 安全配置:
@EnableWebSecurity
public class SpringSecurityConfig
@Configuration
@Order(1)
@EnableGlobalMethodSecurity(securedEnabled = true)
public static class InternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter
@Autowired
private Filter filterA;
public InternalApiConfigurerAdapter()
super(true);
@Override
public void configure(WebSecurity web) throws Exception
web
.ignoring()
.antMatchers("/public/**");
@Override
protected void configure(HttpSecurity http) throws Exception
http
.antMatcher("/iapi/**")
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.authorizeRequests()
.anyRequest().authenticated().and()
.addFilterBefore(filterA, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class);
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return authenticationManager();
@Configuration
@Order(2)
@EnableGlobalMethodSecurity(securedEnabled = true)
public static class ExternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter
@Autowired
private FilterB filterB;
public ExternalApiConfigurerAdapter()
super(true);
@Override
protected void configure(HttpSecurity http) throws Exception
http
.antMatcher("/external/**")
.exceptionHandling().and()
.anonymous().and()
.servletApi().and()
.authorizeRequests()
.anyRequest().authenticated().and()
.addFilterBefore(filterB, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class);
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception
return authenticationManager();
更新:目前我有一个在 web.xml 中声明的过滤器的工作配置。但是,它有与 Spring 上下文分离的缺点(例如,没有自动装配 bean),所以我正在寻找一个更好的利用 Spring 的解决方案。
总结:还有两个问题:
-
仅为特定的 url 添加过滤器 - 在任何配置中使用 beforeFilter(...) 会为该配置的所有 url 添加过滤器。 Antmatchers没有工作。我需要这样的东西:/iapi/captcha/、/external/captcha/、/public/captcha/*。
我有一个完全绕过 Spring Security 的公共 api:(web
.ignoring()
.antMatchers("/public/**");)。我需要绕过 Spring Security 但仍在那里声明一个过滤器,使用 Spring 自动装配但不一定是 Spring Security 功能,因为我的验证码过滤器仅以无状态方式拒绝或转发呼叫。
【问题讨论】:
您说的是Filter A
和Filter B
。它们是您的验证码过滤器的占位符,还是您有真正的实现?如果是这样,您能否相应地更新您的问题?
不确定它是否正是您要找的东西,但发现this answer 有一个类似的问题。不同之处在于它们在链的末尾添加了过滤器,并且配置是 XML 格式的,但是在 javaconfig 中,http.addFilterBefore() 也可以解决问题。
@ksokol 它们是当前系统的过滤器,我不想碰它们。
@SalvadorJuanMartinez 我认为它不会起作用。这是一个 xml 配置,我的主要问题是,我只想在不同配置中的特定路径之前添加一个过滤器 - 所以我不需要更改我的整个设置。
对不起,我想我没有解释清楚,我不是说要更改 XML 配置和/或在末尾添加过滤器,而是可以用作参考,因为它是如何向链中添加自定义过滤器的工作示例。它提供了有关如何正确实现过滤器的信息。在您的情况下,您可以坚持.addFilterBefore()
将过滤器插入您想要的位置。
【参考方案1】:
您已经有了在UsernamePasswordAuthenticationFilter
之前插入过滤器A 和B 的工作配置,因此添加另一个自定义过滤器应该很容易。
首先,您创建过滤器,并将其声明为 bean,或者使用 @Component
注释该类,或者作为 @Configuration
类中的 @Bean
,以便可以使用 @Autowired
注入它.
现在您可以将它作为过滤器 A 和 B 注入并使用它。根据 Spring Security 参考文档中的 Filter Ordering 部分,链中的第一个过滤器是 ChannelProcessingFilter
,因此为了在 Spring Security 过滤器链中的任何其他内容之前插入过滤器,您可以这样做:
@Autowired
private CaptchaFilter captchaFilter;
@Override
protected void configure(HttpSecurity http) throws Exception
http
.antMatcher("/iapi/**")
.addFilterBefore(captchaFilter, (Class<? extends Filter>) ChannelProcessingFilter.class)
.addFilterBefore(filterA, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
顺便说一句,exceptionHandling()
anonymous()
和 servletApi()
不是必需的,因为在扩展 WebSecurityConfigurerAdapter
时,它们已经包含在内,除了 anonymous()
当您实际指定更多配置详细信息时,如它所述 @ 987654322@
请记住,Spring Security“入口点”DelegatingFilterProxy
仍将在您的过滤器之前执行,但该组件仅将请求委托给链中的第一个过滤器,在本例中为 CaptchaFilter,所以你真的会在 Spring Security 执行任何其他操作之前执行你的过滤器。
但是如果你仍然希望验证码过滤器在DelegatingFilterProxy
之前执行,在Spring Security配置中是没有办法的,需要在web.xml
文件中声明。
更新:如果您不想在其他配置中包含验证码过滤器,您可以随时添加第三个配置,配置类如下:
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpringSecurityConfig
@Configuration
@Order(1)
public static class CaptchaApiConfigurerAdatper extends WebSecurityConfigurerAdapter
@Autowired
private CaptchaFilter captchaFilter;
public CaptchaApiConfigurerAdatper()
super(true);
@Override
public void configure(WebSecurity web) throws Exception
web
.ignoring()
.antMatchers("/public/**");
@Override
protected void configure(HttpSecurity http) throws Exception
http
.requestMatchers()
.antMatcher("/iapi/captcha**")
.antMatcher("/external/captcha**")
.and()
.addFilterBefore(captchaFilter, (Class<? extends Filter>) ChannelProcessingFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
@Configuration
@Order(2)
public static class InternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter
// ommiting code for the sake of clarity
@Configuration
@Order(3)
public static class ExternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter
// ommiting code for the sake of clarity
顺便说一句,另一个技巧,您可以将特定配置之外的所有通用配置重构到主类中,例如 @EnableGlobalMethodSecurity(securedEnabled = true)
AuthenticationManager,WebSecurity
为公众跳过安全性,但对于那些自主类没有扩展任何你应该@Autowire
方法声明的东西。
虽然WebSecurity
会有一个问题,但如果您忽略/public/**
,则HttpSecurity
与/public/captcha**
的匹配器将被忽略,所以我想,您不应该重构WebSecurity
和CaptchaConfig 类中的模式不同,因此不会重叠。
【讨论】:
对不起,我已经尝试过这种方法。它会在任何请求上使用这两个过滤器,但我需要特定的路径。另外我仍然不知道如何在非 Spring Security 调用中添加它们。我相应地更新了我的问题。感谢有关异常处理的提示,这些东西有助于我更好地理解 Spring Security! 没有什么可以阻止您为验证码过滤器添加第三个配置,请记住@Order
,我将通过示例更新答案。以上是关于如何仅针对特定 url 添加 Spring Security 验证码过滤器的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 sec:authorize with thymeleaf 向特定用户授权 html 元素?
Spring security:在 3.1 中,仅针对“GET”请求绕过安全过滤器
仅针对 nginx 上的特定 url 使用 https 重定向