java 如何仅针对特定 url 额外添加 Spring Security 验证码过滤器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34314084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Howto additionally add Spring Security captcha filter for specific urls only
提问by Journeycorner
I am looking for a non invasive way to add a captcha filter for certain api calls.
我正在寻找一种非侵入性的方式来为某些 api 调用添加验证码过滤器。
My setup consists of two WebSecurityConfigurerAdapters
with one filter each (not the captcha filter):
我的设置由两个WebSecurityConfigurerAdapters
和一个过滤器组成(不是验证码过滤器):
- Internal api("/iapi" use Filter A on all calls but also ignore some publicrequests like /authenticate)
- External api("/eapi" use Filter B on all calls)
- 内部 api(“/iapi”在所有调用中使用过滤器 A,但也会忽略一些公共请求,例如 /authenticate)
- 外部 api(“/eapi”在所有调用中使用过滤器 B)
How can I add a filter beforethe Spring Security stuff, on public, internal api or external api calls? I don't need the SecurityContext, just need to check for a Captcha in the request headers, forward to filterChain (normal filters) or manually deny access. I tried declaring a filter in web.xml, but that breaks the ability to use dependency injection.
如何在 Spring Security 内容之前,在公共、内部 api 或外部 api 调用上添加过滤器?我不需要 SecurityContext,只需要检查请求标头中的验证码,转发到 filterChain(普通过滤器)或手动拒绝访问。我尝试在 web.xml 中声明一个过滤器,但这破坏了使用依赖注入的能力。
Here is my Spring Security Configuration:
这是我的 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();
}
}
Update:At the moment I have a working configuration with a filter declared in web.xml. However, it has the drawback of being seperated from the Spring Context (e.g. no autowiring of beans), so I am looking for a better solution leveraging Spring.
更新:目前我有一个工作配置,带有在 web.xml 中声明的过滤器。但是,它具有与 Spring 上下文分离的缺点(例如,不能自动装配 bean),因此我正在寻找利用 Spring 的更好解决方案。
Summary: There are two remaining problems:
总结:还有两个问题:
- add a filter for specific urlsonly - using beforeFilter(...) inside any configuration adds a filter to all urls of that configuration. Antmatchers didn't work. I need something like that: /iapi/captcha/, /external/captcha/, /public/captcha/*.
- I have a public api which bypasses Spring Security completely: (web .ignoring() .antMatchers("/public/**");). I need to bypass Spring Security but still declare a filter there, using Spring autowiring but not necessarily Spring Security features, since my captcha filter only rejects or forwards calls in a stateless way.
- 仅为特定 url添加过滤器- 在任何配置中使用 beforeFilter(...) 会向该配置的所有 url 添加过滤器。Antmatchers 没有工作。我需要这样的东西:/iapi/captcha/ 、/external/captcha/、/public/captcha/*。
- 我有一个完全绕过 Spring Security 的公共 api: (web .ignoring() .antMatchers("/public/**");)。我需要绕过 Spring Security 但仍然在那里声明一个过滤器,使用 Spring 自动装配但不一定是 Spring Security 功能,因为我的验证码过滤器仅以无状态方式拒绝或转发调用。
采纳答案by saljuama
You already have a working configuration with filters A and B inserted before UsernamePasswordAuthenticationFilter
so should be easy to add another custom filter.
您已经有一个工作配置,之前插入了过滤器 A 和 B,UsernamePasswordAuthenticationFilter
因此添加另一个自定义过滤器应该很容易。
First, you create the filter, and declare it as a bean, either annotating the class with @Component
, or as a @Bean
inside a @Configuration
class, so it is ready to be injected with @Autowired
.
首先,您创建过滤器,并将其声明为 bean,或者使用 注释该类@Component
,或者作为类的@Bean
内部@Configuration
,以便准备好注入@Autowired
.
Now you are able to inject it, as filter A and B, and use it. According to the Filter Orderingsection in the Spring Security reference documentation, the very first Filter in the chain is ChannelProcessingFilter
, so in order to insert the filter before anything else in the Spring Security filter chain, you'd do this:
现在您可以注入它,作为过滤器 A 和 B,并使用它。根据Spring Security 参考文档中的过滤器排序部分,链中的第一个过滤器是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();
}
By the way, exceptionHandling()
anonymous()
and servletApi()
aren't needed because when extending WebSecurityConfigurerAdapter
, these are already included, except for anonymous()
when you actually specify more configuration details, as it states HttpSecurity
javadoc
顺便说一句,exceptionHandling()
anonymous()
并且servletApi()
不需要,因为在扩展时WebSecurityConfigurerAdapter
,这些已经包含在内,除非anonymous()
您实际指定更多配置详细信息,因为它指出HttpSecurity
javadoc
Keep in mind that the Spring Security "entrypoint", the DelegatingFilterProxy
still will be executed before your filter, but this component only delegates the request to the first filter in the chain, which in this case would be the CaptchaFilter, so you really would execute your filter before anything else from Spring Security.
请记住,Spring Security“入口点”,DelegatingFilterProxy
仍然会在您的过滤器之前执行,但该组件仅将请求委托给链中的第一个过滤器,在这种情况下将是 CaptchaFilter,因此您真的会执行您的在 Spring Security 的其他任何东西之前过滤。
But if you still want the captcha filter be executed before the DelegatingFilterProxy
, there is no way to do so in the Spring Security configuration, and you need to declare it in the web.xml
file.
但是如果你仍然希望在 之前执行验证码过滤器DelegatingFilterProxy
,那么在 Spring Security 配置中没有办法这样做,你需要在web.xml
文件中声明它。
Update: If you do not desire to include the captcha filter in the other configurations, you can always add a third configuration, and the configurations class would be as follows:
更新:如果您不想在其他配置中包含验证码过滤器,您可以随时添加第三个配置,配置类如下:
@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
}
By the way, another tip, you can refactor all the common configuration outside the specific configurations, into the main class, like @EnableGlobalMethodSecurity(securedEnabled = true)
the AuthenticationManager, the WebSecurity
to skip security for the public, but for those since the main class is not extending anything you should @Autowire
the method declarations.
顺便说一句,还有一个小窍门,你可以重构所有常见配置的具体配置之外,进入主类,像@EnableGlobalMethodSecurity(securedEnabled = true)
在的AuthenticationManager,将WebSecurity
跳过安全为公,但对于那些因为主类是不延长任何你应该@Autowire
的方法声明。
Although there would be one problem with the WebSecurity
, if you are ignoring /public/**
the matcher for the HttpSecurity
with /public/captcha**
would be ignored, so i guess, you shouldnt refactor out the WebSecurity
and have a different pattern in the CaptchaConfig class so it doesnt overlap.
尽管 会有一个问题WebSecurity
,如果您忽略/public/**
了HttpSecurity
with的匹配器,/public/captcha**
则将被忽略,所以我想,您不应该重构出WebSecurity
并在 CaptchaConfig 类中使用不同的模式,这样它就不会重叠。