java - 如何仅针对特定 url 额外添加 Spring Security 验证码过滤器

标签 java spring spring-security captcha

我正在寻找一种非侵入性的方式来为某些 api 调用添加验证码过滤器。

我的设置由两个 WebSecurityConfigurerAdapters 组成,每个都有一个过滤器(不是验证码过滤器):

  • 内部 api(“/iapi”在所有调用中使用过滤器 A,但也会忽略一些 public 请求,例如/authenticate)
  • 外部 api(“/eapi”在所有调用中使用过滤器 B)

如何在公共(public)、内部 api 或外部 api 调用中添加过滤器之前 Spring Security 的东西?我不需要SecurityContext,只需要检查请求 header 中的验证码,转发到filterChain(普通过滤器)或手动拒绝访问。我尝试在 web.xml 中声明一个过滤器,但这破坏了使用依赖注入(inject)的能力。

这是我的 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 上下文分离的缺点(例如,没有 Autowiring bean),所以我正在寻找一个更好的利用 Spring 的解决方案。

总结:还有两个问题:

  1. 仅为特定的 url 添加过滤器 - 在任何配置中使用 beforeFilter(...) 会为该配置的所有 url 添加过滤器。 Antmatchers没有工作。我需要类似的东西:/iapi/captcha/、/external/captcha/、/public/captcha/*。
  2. 我有一个完全绕过 Spring Security 的公共(public) api:(web .ignoring() .antMatchers("/public/**");)。我需要绕过 Spring Security 但仍在那里声明一个过滤器,使用 Spring Autowiring 但不一定是 Spring Security 功能,因为我的验证码过滤器仅以无状态方式拒绝或转发调用。

最佳答案

您已经有一个在 UsernamePasswordAuthenticationFilter 之前插入过滤器 A 和 B 的工作配置,因此应该很容易添加另一个自定义过滤器。

首先,您创建过滤器,并将其声明为 bean,或者使用 @Component 注释类,或者作为 @Bean 内的 @ Configuration 类,因此可以使用 @Autowired 进行注入(inject)。

现在您可以将它作为过滤器 A 和 B 注入(inject)并使用它。根据Filter Ordering在 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();
    }

顺便说一下,exceptionHandling() anonymous()servletApi() 是不需要的,因为在扩展 WebSecurityConfigurerAdapter,除了 anonymous() 当您实际指定更多配置详细信息时,这些都已包含在内,因为它指出 HttpSecurity javadoc

请记住,Spring Security “入口点”,DelegatingFilterProxy 仍将在您的过滤器之前执行,但该组件仅将请求委托(delegate)给链中的第一个过滤器,在这种情况下将是 CaptchaFilter,因此您确实会在 Spring Security 的任何其他操作之前执行您的过滤器。

但是如果你仍然希望验证码过滤器在DelegatingFilterProxy之前执行,在Spring Security配置中是没有办法的,需要在web.xml中声明。 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 类中使用不同的模式,因此它不会重叠。

关于java - 如何仅针对特定 url 额外添加 Spring Security 验证码过滤器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34314084/

相关文章:

spring - Spring WebClient 流上传 'POST'

java - Spring Security 与 Spring MVC 不起作用

java - Spring Security MultiHttpSecurity Configuration 以便我可以执行两种类型的身份验证。 JWT token 和 session Cookie

java - JPA 实体连接组合键上的列,日期作为 PK 之一

java - Spring Security OAuth2 从默认过滤器链中禁用 BasicAuthenticationFilter

java - 如何找到 http 请求的 IP 地址或位置?

java - 可选的@PropertySource 位置

java - 在 Iterable 上查找元素

java - Spring Data MongoDB 身份验证错误

java - 如何在Spring Security中为两个不同的URL指定两个不同的登录表单?