我正在尝试在登录过程中添加用户ip验证。如果用户的ip地址不在数据库中,应用程序应该拒绝验证。
**问题:**根据下面的设置,结果表明auth.authenticationProvider()没有替换默认的DaoAuthenticationProvider,而是将UserIpAuthenticationProvider添加为列表中的第一个AuthenticationProvider。
在用户名/密码组合不正确的情况下,框架最终调用UserDetailsService.loadUserByUsername()两次,一次来自UserIpAuthenticationProvider,另一次来自内部DaoAuthenticationProvider,这将引发最终的BadCredentialsException()。
**问题:**是否有任何设置可以在Sping Boot 中设置,以便Spring Security不添加其自己的内部示例DaoAuthenticationProvider,而只使用我的UserIpAuthenticationProvider,它已经具有所有必要的功能(也许通过某种方式替换AuthenticationManagerBuilder,以便能够覆盖userDetailsService()方法?)
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T> userDetailsService(
T userDetailsService) throws Exception {
this.defaultUserDetailsService = userDetailsService;
return apply(new DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>(userDetailsService));
}
**配置:**据我所知,UserDetailsService应该提供有关用户的所有必要详细信息,以便AuthenticationProvider可以决定身份验证是否成功。
由于所有必要的信息都是从数据库加载的,因此扩展DaoAuthenticationProvider并在覆盖的additionalAuthenticationChecks()方法中添加额外的验证似乎是很自然的(白名单IP列表位于数据库中,因此它们作为IpAwareUser中用户对象的一部分加载)。
@Named
@Component
class UserIpAuthenticationProvider extends DaoAuthenticationProvider {
@Inject
public UserIpAuthenticationProvider(UserDetailsService userDetailsService)
{
...
}
@SuppressWarnings("deprecation")
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
super.additionalAuthenticationChecks(userDetails, authentication);
WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
IpAwareUser ipAwareUser = (IpAwareUser) userDetails;
if (!ipAwareUser.isAllowedIp(details.getRemoteAddress()))
{
throw new DisabledException("Login restricted from ip: " + details.getRemoteAddress());
}
}
}
这将被注入到SecurityConfiguration中:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilter(authenticationFilter);
http.authorizeRequests()
.antMatchers("/", "/javascript/**", "/css/**").permitAll()
.antMatchers("...").access("...")
.anyRequest().authenticated()
.and().formLogin().loginPage("/").permitAll()
.and().logout().invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll()
.and().csrf().disable()
;
}
@Inject
private UserDetailsService userDetailsService;
@Inject
private UserIpAuthenticationProvider userIpAuthenticationProvider;
@Inject
private JsonUsernamePasswordAuthenticationFilter authenticationFilter;
@Bean
public JsonUsernamePasswordAuthenticationFilter authenticationFilter() {
return new JsonUsernamePasswordAuthenticationFilter();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(userIpAuthenticationProvider);
auth.userDetailsService(userDetailsService);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() throws Exception {
return new JsonAuthenticationSuccessHandler();
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler() throws Exception {
return new JsonAuthenticationFailureHandler();
}
}
和应用程序配置:
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackageClasses = {SecurityConfiguration.class, DataController.class, DaoService.class})
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application;
}
}
我们将非常感谢对此提供任何指导。
2条答案
按热度按时间vecaoik11#
关于这个问题的评论包含了答案:
@ArunM:你项目给了我一个想法:我不需要调用auth.userDetailsService(用户详细信息服务);在SecurityConfiguration.configure()中,这将阻止创建内部DaoAuthenticationProvider!我UserIpAuthenticationProvider可以通过注入获取UserDetailsService的示例。
AuthenticationManagerBuilder.userDetailsService
方法不仅设置默认的UserDetailsService
,而且应用注册DaoAuthenticationProvider
的DaoAuthenticationConfigurer
。如果你想要一个自定义的
DaoAuthenticationProvider
,在构造函数中将UserDetailsService
传递给提供者或者注入它。为了防止默认的DaoAuthenticationProvider
被注册,不要调用AuthenticationManagerBuilder.userDetailsService
。这也在本Spring Security issue中提到。
qojgxg4l2#
定义您自己的DaoAuthenticationProvider
应替换Sping Boot 默认示例(而不是Bean类型为DaoAuthenticationProvider,不是UserIpAuthenticationProvider)