如何仅针对特定网址另外添加 Spring 安全验证码过滤器
Howto additionally add Spring Security captcha filter for specific urls only
我正在寻找一种非侵入性的方法来为某些 api 调用添加验证码过滤器。
我的设置包含两个 WebSecurityConfigurerAdapters
,每个都有一个过滤器(不是验证码过滤器):
- 内部api(“/iapi”在所有调用中使用过滤器 A 但也会忽略一些 public 像 /authenticate)
这样的请求
- 外部 api(“/eapi”在所有调用中使用过滤器 B)
如何在 Spring 安全性内容 之前 添加过滤器 public、内部 api 或外部 api 电话?我不需要 SecurityContext,只需要在请求 headers 中检查验证码,转发到 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.
的更好解决方案
总结:还有两个问题:
- 仅为特定网址添加过滤器 - 在任何配置中使用 beforeFilter(...) 会向该配置的所有网址添加过滤器。 Antmatchers 没有工作。我需要这样的东西:/iapi/captcha/、/external/captcha/、/public/captcha/*.
- 我有一个 public api 完全绕过了 Spring 安全:(web
.忽略()
.antMatchers("/public/**");。我需要绕过 Spring 安全,但仍然在那里声明一个过滤器,使用 Spring 自动装配但不一定 Spring 安全功能,因为我的验证码过滤器只以无状态的方式拒绝或转发呼叫。
您已经有一个工作配置,在 UsernamePasswordAuthenticationFilter
之前插入了过滤器 A 和 B,因此添加另一个自定义过滤器应该很容易。
首先,您创建过滤器,并将其声明为一个 bean,或者用 @Component
注释 class,或者作为 @Configuration
中的 @Bean
class,所以准备注入@Autowired
.
现在您可以将其作为过滤器 A 和 B 注入并使用。根据 Spring 安全参考文档中的 Filter Ordering 部分,链中的第一个过滤器是 ChannelProcessingFilter
,因此为了在 [=64= 中的任何其他内容之前插入过滤器] 安全过滤器链,你会这样做:
@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()
当您实际指定更多配置详细信息时,如它所述 HttpSecurity
javadoc
请记住 Spring 安全性 "entrypoint",DelegatingFilterProxy
仍将在您的过滤器之前执行,但此组件仅将请求委托给链中的第一个过滤器,在本例中是 CaptchaFilter,所以你真的会在 Spring Security.
的任何其他事情之前执行你的过滤器
但是如果你还想在DelegatingFilterProxy
之前执行验证码过滤,在Spring安全配置中是没有办法的,需要在[=]中声明26=] 文件.
更新:如果你不想在其他配置中包含验证码过滤器,你可以随时添加第三个配置,配置class如下:
@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
}
对了,还有个小技巧,你可以重构所有在特定配置之外的通用配置,进入mainclass,像@EnableGlobalMethodSecurity(securedEnabled = true)
AuthenticationManager,WebSecurity
跳过public 的安全性,但对于那些因为主要 class 没有扩展任何东西你应该 @Autowire
方法声明。
虽然 WebSecurity
会有一个问题,但如果您忽略 /public/**
,HttpSecurity
和 /public/captcha**
的匹配器将被忽略,所以我猜,您不应该重构 WebSecurity
并在 CaptchaConfig class 中使用不同的模式,这样它就不会重叠。
我正在寻找一种非侵入性的方法来为某些 api 调用添加验证码过滤器。
我的设置包含两个 WebSecurityConfigurerAdapters
,每个都有一个过滤器(不是验证码过滤器):
- 内部api(“/iapi”在所有调用中使用过滤器 A 但也会忽略一些 public 像 /authenticate) 这样的请求
- 外部 api(“/eapi”在所有调用中使用过滤器 B)
如何在 Spring 安全性内容 之前 添加过滤器 public、内部 api 或外部 api 电话?我不需要 SecurityContext,只需要在请求 headers 中检查验证码,转发到 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.
的更好解决方案总结:还有两个问题:
- 仅为特定网址添加过滤器 - 在任何配置中使用 beforeFilter(...) 会向该配置的所有网址添加过滤器。 Antmatchers 没有工作。我需要这样的东西:/iapi/captcha/、/external/captcha/、/public/captcha/*.
- 我有一个 public api 完全绕过了 Spring 安全:(web .忽略() .antMatchers("/public/**");。我需要绕过 Spring 安全,但仍然在那里声明一个过滤器,使用 Spring 自动装配但不一定 Spring 安全功能,因为我的验证码过滤器只以无状态的方式拒绝或转发呼叫。
您已经有一个工作配置,在 UsernamePasswordAuthenticationFilter
之前插入了过滤器 A 和 B,因此添加另一个自定义过滤器应该很容易。
首先,您创建过滤器,并将其声明为一个 bean,或者用 @Component
注释 class,或者作为 @Configuration
中的 @Bean
class,所以准备注入@Autowired
.
现在您可以将其作为过滤器 A 和 B 注入并使用。根据 Spring 安全参考文档中的 Filter Ordering 部分,链中的第一个过滤器是 ChannelProcessingFilter
,因此为了在 [=64= 中的任何其他内容之前插入过滤器] 安全过滤器链,你会这样做:
@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()
当您实际指定更多配置详细信息时,如它所述 HttpSecurity
javadoc
请记住 Spring 安全性 "entrypoint",DelegatingFilterProxy
仍将在您的过滤器之前执行,但此组件仅将请求委托给链中的第一个过滤器,在本例中是 CaptchaFilter,所以你真的会在 Spring Security.
但是如果你还想在DelegatingFilterProxy
之前执行验证码过滤,在Spring安全配置中是没有办法的,需要在[=]中声明26=] 文件.
更新:如果你不想在其他配置中包含验证码过滤器,你可以随时添加第三个配置,配置class如下:
@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
}
对了,还有个小技巧,你可以重构所有在特定配置之外的通用配置,进入mainclass,像@EnableGlobalMethodSecurity(securedEnabled = true)
AuthenticationManager,WebSecurity
跳过public 的安全性,但对于那些因为主要 class 没有扩展任何东西你应该 @Autowire
方法声明。
虽然 WebSecurity
会有一个问题,但如果您忽略 /public/**
,HttpSecurity
和 /public/captcha**
的匹配器将被忽略,所以我猜,您不应该重构 WebSecurity
并在 CaptchaConfig class 中使用不同的模式,这样它就不会重叠。