在用户身份验证上,我需要检索他的远程地址和远程主机
我正在尝试实现自定义过滤器以支持此功能,但我得到“ authenticationManager必须指定”。
另一个疑问是......使用编程方式注册自定义过滤器的正确方法是什么?
使用注释进行配置:
@Configuration
@EnableWebSecurity
public class SecurityApplicationConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private SCAAuthenticationFilter scaAuthenticationFilter;
@Autowired
private SCAAuthenticationProvider scaAuthenticationProvider;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(scaAuthenticationProvider);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(scaAuthenticationFilter) // What is the right way ?
.addFilterBefore(scaAuthenticationFilter, AbstractAuthenticationProcessingFilter.class) // What is the right way ?
.csrf().disable()
.authorizeRequests()
.antMatchers("/manual/**").authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/manual")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.permitAll()
.and();
}
}
自定义过滤器:
@Component
public class SCAAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
String remoteHost = request.getRemoteHost();
String remoteAddr = request.getRemoteAddr();
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
SCAAuthenticationToken scaAuthenticationToken = new SCAAuthenticationToken(username, password, remoteHost, remoteAddr);
setDetails(request, scaAuthenticationToken);
return getAuthenticationManager().authenticate(scaAuthenticationToken);
}
}
答案 0 :(得分:4)
您需要为扩展过滤器设置authenticationManagerBean并将其配置为corr
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public ExUsernamePasswordAuthenticationFilter exUsernamePasswordAuthenticationFilter()
throws Exception {
ExUsernamePasswordAuthenticationFilter exUsernamePasswordAuthenticationFilter = new ExUsernamePasswordAuthenticationFilter();
exUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
return exUsernamePasswordAuthenticationFilter;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
RequestMatcher requestMatcher = new RequestMatcher() {
@Override
public boolean matches(HttpServletRequest httpServletRequest) {
if (httpServletRequest.getRequestURI().indexOf("/api", 0) >= 0) {
return true;
}
return false;
}
};
http
.addFilterBefore(exUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
...
}
}
答案 1 :(得分:2)
您的自定义过滤器扩展了Spring Security的UsernamePasswordAuthenticationFilter
,这意味着它需要对身份验证管理器的引用。我会在安全配置中将您的过滤器设置为@Bean
,然后按照this answer说明获取AuthenticationManager
引用的不同选项。
答案 2 :(得分:1)
在扩展WebSecurityConfigurerAdapter的类中,重写authenticationManagerBean()方法并使用@Bean注释它:
@Configuration
@EnableWebMvcSecurity
public class YourCustomConfig extends WebSecurityConfigurerAdapter{
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
现在,您将能够在其他类中@Autowire AuthenticationManager。
答案 3 :(得分:0)
另一个选择是为过滤器创建一个配置器,并将所有与过滤器初始化有关的工作委托给它(通过UsernamePasswordAuthenticationFilter
配置FormLoginConfigurer
和AbstractAuthenticationProcessingFilter
的配置方式相同) AbstractAuthenticationFilterConfigurer
)。
public class SCAAuthenticationConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>() {
public static SCAAuthenticationConfigurer scaAuthentication() {
return new SCAAuthenticationConfigurer()
}
@Override
public void configure(HttpSecurity http) throws Exception {
SCAAuthenticationFilter filter = new SCAAuthenticationFilter()
filter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
// add postProcess(filter) call if require to autowire some fields
http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
}
}
有了这样的配置器,您的SecurityConfig
会看起来更整洁:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.apply(scaAuthentication())
.and()
// do the rest of configuration
}
}
您甚至可以将过滤器初始化委派给ApplicationContext(例如,如果您有要注入的配置):
public class FilterWithSettingsConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>() {
@Configuration
@EnableConfigurationProperties(SomeSettings.class)
private static class Config {}
@Override
public void configure(HttpSecurity http) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()
context.parent = http.getSharedObject(ApplicationContext.class)
context.register(Config.class)
context.refresh()
FilterWithSettings filter =
context.getAutowireCapableBeanFactory().createBean(FilterWithSettings.class)
filter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class)
}
}