如何使用 Java 配置表示 Spring Security“自定义过滤器”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/24122586/
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
How to represent the Spring Security "custom-filter" using Java configuration?
提问by user3722706
What is the equivalent Java configuration for the Spring Security <custom-filter>tag?
Spring Security<custom-filter>标签的等效 Java 配置是什么?
<http>
  <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>
</http>
I tried
我试过
http.addFilter( new MyUsernamePasswordAuthenticationFilter() )
where the class extends the default filter, but it always employs the formLogindefault.
其中该类扩展了默认过滤器,但它始终使用formLogin默认值。
My filter:
我的过滤器:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter{
    // proof of concept of how the http.addFilter() works
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        System.out.println("running my own version of UsernmePasswordFilter ... ");
        String username = obtainUsername(request);
        String password = obtainPassword(request);
        if (username == null) {
            username = "";
        }
        if (password == null) {
            password = "";
        }
        username = username.trim();
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}
The relevant configuration piece:
相关配置片:
@Configuration
@EnableWebMvcSecurity  // annotate class configuring AuthenticationManagerBuilder
@ComponentScan("com.kayjed")
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http
        .authorizeRequests()
            .antMatchers("/resources/**","/signup").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
        .logout()
            .permitAll();
      http.addFilter(new MyUsernamePasswordAuthenticationFilter());
    }
    ...
}
Running the MVC app in the debugger always shows the login attempts authentication from the default UsernamePasswordAuthenticationFilterinstead of my intention of employing the MyUsernamePasswordAuthenticationFilterclass.
在调试器中运行 MVC 应用程序总是显示默认的登录尝试身份验证,UsernamePasswordAuthenticationFilter而不是我打算使用MyUsernamePasswordAuthenticationFilter该类。
Anyways, I am not trying to get someone to debug code; rather, I would love to see a good example using Java configuration that performs the equivalent of the custom-filter element in the XML approach. The documentation is a bit terse.
无论如何,我并不是要找人调试代码;相反,我希望看到一个使用 Java 配置的好示例,该示例在 XML 方法中执行与 custom-filter 元素等效的操作。该文档有点简洁。
回答by programsji.com
I dont find any issue in this code. I think, your configuration is fine. Problem is somewhere else.I have similar code,
我在这段代码中没有发现任何问题。我觉得,你的配置没问题。问题出在别处。我有类似的代码,
package com.programsji.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import com.programsji.security.CustomAuthenticationProvider;
import com.programsji.security.CustomSuccessHandler;
import com.programsji.security.CustomUsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/theme/**").and()
                .debug(true);
    }
    @Bean
    public CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter()
            throws Exception {
        CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
        customUsernamePasswordAuthenticationFilter
                .setAuthenticationManager(authenticationManagerBean());
        customUsernamePasswordAuthenticationFilter
                .setAuthenticationSuccessHandler(customSuccessHandler());
        return customUsernamePasswordAuthenticationFilter;
    }
    @Bean
    public CustomSuccessHandler customSuccessHandler() {
        CustomSuccessHandler customSuccessHandler = new CustomSuccessHandler();
        return customSuccessHandler;
    }
    @Bean
    public CustomAuthenticationProvider customAuthenticationProvider() {
        CustomAuthenticationProvider customAuthenticationProvider = new CustomAuthenticationProvider();
        return customAuthenticationProvider;
    }
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        List<AuthenticationProvider> authenticationProviderList = new ArrayList<AuthenticationProvider>();
        authenticationProviderList.add(customAuthenticationProvider());
        AuthenticationManager authenticationManager = new ProviderManager(
                authenticationProviderList);
        return authenticationManager;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/reportspage").hasRole("REPORT")
                .antMatchers("/rawdatapage").hasRole("RAWDATA").anyRequest()
                .hasRole("USER").and().formLogin().loginPage("/login")
                .failureUrl("/login?error")
                .loginProcessingUrl("/j_spring_security_check")
                .passwordParameter("j_password")
                .usernameParameter("j_username").defaultSuccessUrl("/")
                .permitAll().and().httpBasic().and().logout()
                .logoutSuccessUrl("/login?logout").and().csrf().disable()
                .addFilter(customUsernamePasswordAuthenticationFilter());
    }
}
It is working fine on my application. you can download this entire project from url: https://github.com/programsji/rohit/tree/master/UsernamePasswordAuthenticationFilter
它在我的应用程序上运行良好。你可以从 url 下载整个项目:https: //github.com/programsji/rohit/tree/master/UsernamePasswordAuthenticationFilter
回答by Denis C de Azevedo
Try to add @Componentto your MyUsernamePasswordAuthenticationFilterclass.
尝试添加@Component到您的MyUsernamePasswordAuthenticationFilter班级。
This annotation makes the class considered as candidates for auto-detection, see: @Component
此注释使类被视为自动检测的候选对象,请参阅: @Component
For this:
为了这:
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>
You can add this:
你可以添加这个:
.addFilter[Before|After](authenticationTokenProcessingFilter, UsernamePasswordAuthenticationFilter.class)
See: Standard Filter Aliases and Ordering
请参阅:标准过滤器别名和排序
回答by Aner
A few issues you may need to keep in mind:
您可能需要牢记以下几个问题:
- Your filter needs to be added beforethe standard - UsernamePasswordAuthenticationFilter- http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
- If you extend UsernamePasswordAuthenticationFilter your filter will return immediately without doing anything unless you set a - RequestMatcher- myAuthFilter.setRequiresAuthenticationRequestMatcher( new AntPathRequestMatcher("/login","POST"));
- All the configuration you do in - http.formLogin().x().y().z()is applied to the standard- UsernamePasswordAuthenticationFilternot the custom filter you build. You will need to configure it manually yourself. My auth filter initialization looks like this:- @Bean public MyAuthenticationFilter authenticationFilter() { MyAuthenticationFilter authFilter = new MyAuthenticationFilter(); authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST")); authFilter.setAuthenticationManager(authenticationManager); authFilter.setAuthenticationSuccessHandler(new MySuccessHandler("/app")); authFilter.setAuthenticationFailureHandler(new MyFailureHandler("/login?error=1")); authFilter.setUsernameParameter("username"); authFilter.setPasswordParameter("password"); return authFilter; }
- 您的过滤器需要在标准之前添加 - UsernamePasswordAuthenticationFilter- http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
- 如果您扩展 UsernamePasswordAuthenticationFilter 您的过滤器将立即返回而不做任何事情,除非您设置 - RequestMatcher- myAuthFilter.setRequiresAuthenticationRequestMatcher( new AntPathRequestMatcher("/login","POST"));
- 您所做的所有配置 - http.formLogin().x().y().z()都应用于标准,- UsernamePasswordAuthenticationFilter而不是您构建的自定义过滤器。您需要自己手动配置它。我的身份验证过滤器初始化如下所示:- @Bean public MyAuthenticationFilter authenticationFilter() { MyAuthenticationFilter authFilter = new MyAuthenticationFilter(); authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST")); authFilter.setAuthenticationManager(authenticationManager); authFilter.setAuthenticationSuccessHandler(new MySuccessHandler("/app")); authFilter.setAuthenticationFailureHandler(new MyFailureHandler("/login?error=1")); authFilter.setUsernameParameter("username"); authFilter.setPasswordParameter("password"); return authFilter; }

