如何使用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 10:17:38  来源:igfitidea点击:

How to represent the Spring Security "custom-filter" using Java configuration?

javaspring-securityspring-java-config

提问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:

您可能需要牢记以下几个问题:

  1. Your filter needs to be added beforethe standard UsernamePasswordAuthenticationFilter

    
    http.addFilterBefore(customUsernamePasswordAuthenticationFilter(),
            UsernamePasswordAuthenticationFilter.class)
    
  2. If you extend UsernamePasswordAuthenticationFilter your filter will return immediately without doing anything unless you set a RequestMatcher

    
    myAuthFilter.setRequiresAuthenticationRequestMatcher(
        new AntPathRequestMatcher("/login","POST"));
    
  3. 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;
    }
    
  1. 您的过滤器需要在标准之前添加UsernamePasswordAuthenticationFilter

    
    http.addFilterBefore(customUsernamePasswordAuthenticationFilter(),
            UsernamePasswordAuthenticationFilter.class)
    
  2. 如果您扩展 UsernamePasswordAuthenticationFilter 您的过滤器将立即返回而不做任何事情,除非您设置 RequestMatcher

    
    myAuthFilter.setRequiresAuthenticationRequestMatcher(
        new AntPathRequestMatcher("/login","POST"));
    
  3. 您所做的所有配置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;
    }