Как представить пользовательский фильтр 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-подходе. Документация немного краткая.
Ответы
Ответ 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)
Смотрите: Стандартные псевдонимы фильтра и порядок