gpt4 book ai didi

java - Spring Boot 初始化了比预期更多的 DaoAuthenticationProvider

转载 作者:行者123 更新时间:2023-12-02 11:38:16 24 4
gpt4 key购买 nike

我正在与苹果最近在 OS X 中遇到的一个“错误”作斗争:) 一个应用程序对用户进行身份验证,不仅将其密码字段视为 bcrypt 哈希值,而且还视为明文,因此它允许特殊的实用程序帐户进行登录使用空密码。

数据库中有大量用户记录,几乎所有记录的密码都经过 bcrypt 哈希处理。然而,有一些特殊的实用程序帐户的密码哈希字段故意留空(以使 BcryptPasswordEncoder#matches 始终拒绝它们的登录尝试)。

ProviderManager 上放置断点,我可以看到由 spring 初始化的多个身份验证提供程序:

  • 带有 bcrypt 编码器的“正确”DaoAuthenticationProvider
  • AnonymousAuthenticationProvider,没有人配置,但至少我可以猜测它来自 permitAll() 或类似的东西。
  • 一个不需要的 DaoAuthenticationProviderPlaintextPasswordEncoder 破坏了所有乐趣

我们有另一个项目,我们不使用 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);
}

}

编辑:如果我正确的话,有一种方法可以配置全局和本地 AuthenticationManagerBuilder:

// 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 个提供者:匿名和明文。身份验证行为仍然存在,应用程序仍然使用两者并允许用户使用明文密码登录。取消注释 configureGlobal 也没有帮助,在这种情况下,全局管理器包含所有三个提供程序。

最佳答案

该配置在多个位置显式提供 userDetailsS​​ervice,而不提供 PasswordEncoder。最简单的解决方案是将 UserDetaisService 和 PasswordEncoder 作为 Bean 公开,并删除所有显式配置。这是可行的,因为如果没有显式配置,Spring Security 将发现 Bean 并从中创建身份验证。

@Configuration
@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http // Don't forget to remove 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();
}
// UserDetailsService appears to be a Bean somewhere else, but make sure you have one defined as a Bean
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(15);
}

}

失败的原因是因为有显式配置来使用 UserDetailsS​​ervice 两次:

@Autowired
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// below Configures UserDetailsService with no PasswordEncoder
auth.userDetailsService(userDetailsService);
// configures the same UserDetailsService (it was used to create the authenticationProvider) with a PasswordEncoder (it was provided to the authenticationProvider)
auth.authenticationProvider(authenticationProvider);
}

如果您想要显式配置,可以使用以下内容

@Override
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}

并删除 authenticationProvider bean 以及 @Autowired AuthenticationProvider。或者,您可以只使用 AuthenticationProvider,但不能同时使用两者。

通常,只有当您有多个具有不同身份验证机制的 WebSecurityConfigurerAdapter 时,才需要显式配置 AuthenticationManagerBuilder。如果您不需要这样做,我建议仅将 UserDetailsS​​ervice 和(可选)PasswordEncoder 作为 Bean 公开。

请注意,如果您将 AuthenticationProvider 公开为 Bean,它将通过 UserDetailsS​​ervice 使用。同样,如果您将 AuthenticationManager 公开为 Bean,则它将通过 AuthenticationProvider 使用。最后,如果您显式提供 AuthenticationManagerBuilder 配置,它将用于任何 Bean 定义。

关于java - Spring Boot 初始化了比预期更多的 DaoAuthenticationProvider,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48767183/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com