如何使用 Java 配置表示 Spring Security“自定义过滤器”?

Posted

技术标签:

【中文标题】如何使用 Java 配置表示 Spring Security“自定义过滤器”?【英文标题】:How to represent the Spring Security "custom-filter" using Java configuration? 【发布时间】:2014-07-30 03:06:36 【问题描述】:

Spring Security <custom-filter> 标签的等效 Java 配置是什么?

<http>
  <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>
</http>

我试过了

http.addFilter( new MyUsernamePasswordAuthenticationFilter() )

该类扩展了默认过滤器,但它始终使用formLogin 默认值。

我的过滤器:

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);
    

相关配置块:

@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());
    

    ...

在调试器中运行 MVC 应用程序始终显示登录尝试从默认 UsernamePasswordAuthenticationFilter 进行身份验证,而不是我打算使用 MyUsernamePasswordAuthenticationFilter 类。

无论如何,我并不是要找人调试代码;相反,我希望看到一个使用 Java 配置的好示例,该配置在 XML 方法中执行与自定义过滤器元素等效的操作。文档有点简洁。

【问题讨论】:

请发布您的整个配置并描述“它始终使用 formLogin 默认值”的意思 【参考方案1】:

您可能需要记住几个问题:

    您的过滤器需要标准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;
    
    

【讨论】:

您还可以通过 MyAuthenticationFilter 的重写 setAuthenticationManager() setter 获取 default AuthenticationManager 实例。 @Altair7852 你能分享一个关于 MyAuthenticationFilter 的项目吗 @noodles,MyAuthenticationFilter 是他对 UsernamePasswordAuthenticationFilter 的实现。【参考方案2】:

我在这段代码中没有发现任何问题。我认为,你的配置很好。问题出在其他地方。我有类似的代码,

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());
    


它在我的应用程序上运行良好。 您可以从 url 下载整个项目: https://github.com/programsji/rohit/tree/master/UsernamePasswordAuthenticationFilter

【讨论】:

您提供的链接已离线。【参考方案3】:

尝试将@Component 添加到您的MyUsernamePasswordAuthenticationFilter 类中。

此注释使该类被视为自动检测的候选者,请参阅: @Component


为此:

<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter"/>

你可以添加这个:

.addFilter[Before|After](authenticationTokenProcessingFilter, UsernamePasswordAuthenticationFilter.class)

见:Standard Filter Aliases and Ordering

【讨论】:

也许您可以解释一下为什么您认为这可以解决问题? 您找到解决问题的方法了吗?我正在寻找完全相同的东西。感谢您分享您的解决方案,如果有的话。

以上是关于如何使用 Java 配置表示 Spring Security“自定义过滤器”?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security sec:使用 Java Config 授权标签

如何在 Spring sec 中为组使用属性:hasAnyRole 的授权标签

如何在 Spring Security thymeleaf sec 中使用列表:授权标签

Spring IOC容器

如何在 Spring Security 的同一个请求中使用两个身份验证提供程序?

多个登录页面的 Spring 3.x 配置