Подтвердить что ты не робот

Как представить пользовательский фильтр Spring Security с использованием конфигурации Java?

Какова эквивалентная конфигурация Java для тега Spring Security <custom-filter>?

<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-подходе. Документация немного краткая.

4b9b3361

Ответ 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;
    }
    

Ответ 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.

В этой аннотации класс рассматривается как кандидат на автоматическое обнаружение, см. @Компонент


Для этого:

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

Вы можете добавить это:

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

Смотрите: Стандартные псевдонимы фильтра и порядок