【发布时间】:2018-02-15 03:03:08
【问题描述】:
我正在与 Apple 最近在 OS X 中遇到的一个“错误”作斗争 :) 一个应用程序对用户进行身份验证,不仅将其密码字段视为 bcrypt 散列,而且还视为明文,因此它允许特殊实用程序帐户登录密码为空。
数据库中有一堆用户记录,几乎所有的用户记录都用 bcrypt 散列了密码。然而,有一些特殊的实用程序帐户的密码哈希字段故意留空(以使BcryptPasswordEncoder#matches 始终拒绝他们的登录尝试)。
在ProviderManager 各处放置断点我可以看到spring 初始化了多个身份验证提供程序:
- 带有 bcrypt 编码器的“正确”
DaoAuthenticationProvider -
AnonymousAuthenticationProvider,没有人配置,但至少我可以猜到它来自permitAll()或类似的东西。 - 不受欢迎的
DaoAuthenticationProvider和PlaintextPasswordEncoder破坏了所有乐趣
我们有另一个项目,我们不使用 Spring Boot,并且具有几乎相同的配置,它按预期工作(密码永远不会被视为纯文本,仅作为 bcrypt 哈希)。所以我的猜测是:这个“问题”与 Spring Boot“按约定配置”有关,我找不到如何覆盖它的行为。
在这个项目中,我使用以下配置:
@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
AuthenticationProvider authenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsService)
.authorizeRequests()
.antMatchers("/js/**", "/css/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.loginProcessingUrl("/j_spring_security_check").permitAll()
.successHandler(new SuccessHandler())
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).permitAll()
.logoutSuccessUrl("/login");
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
@Autowired
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider);
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
final DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(15);
}
}
编辑:如果我理解正确,有一种方法可以配置全局和本地 AuthenticationManagerBuilders:
// Inject and configure global:
/*
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
*/
// Override method and configure the local one:
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
这样做,我现在有两个构建器实例:一个 - 本地 - 只有正确的管理器:bcrypt,另一个 - 全局 - 有其他 2 个提供者:匿名和纯文本。身份验证行为仍然存在,应用程序仍然使用 both 并允许用户使用明文密码登录。取消注释 configureGlobal 也无济于事,在这种情况下,全局管理器包含所有三个提供程序。
【问题讨论】:
-
这是不工作的。我会在一分钟内尝试...
-
不,不走运。出于某种原因,仍然存在所有 3 个身份验证提供程序。
this.authenticationProviders.add(authenticationProvider);被多次调用,仍然可以使用明文密码登录。 -
我现在很困惑。我在
AuthenticationManagerBuilder#authenticationProvider方法中设置了一个断点,我清楚地看到在应用程序启动期间配置了两个AuthenticationManagerBuilders:它们是,例如AuthenticationManagerBuilder@7702 和WebSecurityConfigurerAdapter@7745。第一个单独获得正确的提供者。后一个添加了所有 3 个身份验证提供程序。另外,我已按照您的建议删除了@Autowired。 -
请不要在标题中添加“[已解决]”或在问题中添加答案。如果现有答案解决了问题,则通过选择答案分数下方的勾号将其标记为“已接受”。如果您的解决方案与现有答案显着不同,请将其发布为您自己的答案并接受。
标签: java authentication spring-boot spring-security