Spring Security 5:没有为id“null”映射PasswordEncoder

我正在从Spring Boot 1.4.9迁移到Spring Boot 2.0以及Spring Security 5,我正在尝试通过OAuth 2进行身份validation。但是我收到此错误:

java.lang.IllegalArgumentException:没有为id“null”映射PasswordEncoder

从Spring Security 5的文档中,我了解到密码的存储格式已更改。

在我当前的代码中,我创建了我的密码编码器bean:

@Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } 

但它给了我以下错误:

编码密码看起来不像BCrypt

所以我按照Spring Security 5文档更新编码器:

 @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } 

现在,如果我能在数据库中看到密码,那么它就是存储的

 {bcrypt}$2a$10$LoV/3z36G86x6Gn101aekuz3q9d7yfBp3jFn7dzNN/AL5630FyUQ 

随着第一个错误消失,现在当我尝试进行身份validation时,我得到以下错误:

java.lang.IllegalArgumentException:没有为id“null”映射PasswordEncoder

为了解决这个问题,我尝试了Stackoverflow的以下所有问题:

  • Spring Boot PasswordEncoder错误

  • Spring Oauth2。 密码编码器未在DaoAuthenticationProvider中设置

这是一个类似于我的问题,但没有回答:

  • Spring Security 5 – 密码迁移

注意:我已将加密密码存储在数据库中,因此无需再在UserDetailsService进行编码。

在Spring security 5文档中,他们建议您可以使用以下方法处理此exception:

DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(的PasswordEncoder)

如果这是修复,那么我应该把它放在哪里? 我试着将它放在PasswordEncoder bean中,如下所示,但它无法正常工作:

 DelegatingPasswordEncoder def = new DelegatingPasswordEncoder(idForEncode, encoders); def.setDefaultPasswordEncoderForMatches(passwordEncoder); 

MyWebSecurity类

 @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Override public void configure(WebSecurity web) throws Exception { web .ignoring() .antMatchers(HttpMethod.OPTIONS) .antMatchers("/api/user/add"); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } 

MyOauth2配置

 @Configuration @EnableAuthorizationServer protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Bean public TokenStore tokenStore() { return new InMemoryTokenStore(); } @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Bean public TokenEnhancer tokenEnhancer() { return new CustomTokenEnhancer(); } @Bean public DefaultAccessTokenConverter accessTokenConverter() { return new DefaultAccessTokenConverter(); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore()) .tokenEnhancer(tokenEnhancer()) .accessTokenConverter(accessTokenConverter()) .authenticationManager(authenticationManager); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients .inMemory() .withClient("test") .scopes("read", "write") .authorities(Roles.ADMIN.name(), Roles.USER.name()) .authorizedGrantTypes("password", "refresh_token") .secret("secret") .accessTokenValiditySeconds(1800); } } 

请指导我这个问题。 我花了好几个小时来解决这个问题,但无法修复。

在配置ClientDetailsServiceConfigurer ,还必须将新密码存储格式应用于客户机密钥。

 .secret("{noop}secret") 

对于任何面临同样问题并且不需要安全解决方案的人 – 主要用于测试和调试 – 在内存中仍然可以配置用户。

这只是为了玩游戏 – 没有现实世界的场景。

以下使用的方法已弃用。

这是我得到它的地方:

  • 资源
  • 参考,也在上面的来源中提到

在您的WebSecurityConfigurerAdapter添加以下内容:

 @SuppressWarnings("deprecation") @Bean public static NoOpPasswordEncoder passwordEncoder() { return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); } 

显然,密码是经过哈希处理的,但仍可在内存中使用。


当然,您也可以使用像BCryptPasswordEncoder这样的真实PasswordEncoder并在密码前加上正确的id:

 // Create an encoder with strength 16 BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16); String result = encoder.encode("myPassword"); assertTrue(encoder.matches("myPassword", result));