oder mapped for the id \"" + id + "\"");
}
}
可以看到,DelegatingPasswordEncoder 里面 PREFIX 和 SUFFIX 是常量,idForEncode、passwordEncoderForEncode 和idToPasswordEncoder 是在构造方法中传入决定并不可修改的。只有 defaultPasswordEncoderForMatches 是有一个setDefaultPasswordEncoderForMatches 方法进行设置的可变对象。
而且它有一个私有的默认实现 UnmappedIdPasswordEncoder,这个所谓的默认实现的唯一作用就是抛出异常提醒你要自己选择一个默认密码编码器来取代它。通常我们只会可能用到它的 matches 方法,这个时候就会报抛出如下异常:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233)
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196)
5 解决方法
遇到这个异常,最简单的做法就是明确提供一个 PasswordEncoder 对密码进行编码。如果是 从Spring Security 5.0 之前迁移而来的,由于之前默认使用的是 NoOpPasswordEncoder 并且数据库的密码保存格式不带有加密算法 id 头,会报 id 为 null 异常,所以应该明确提供一个NoOpPasswordEncoder 密码编码器。
这里有两种思路:其一就是使用 NoOpPasswordEncoder 取代 DelegatingPasswordEncoder 以恢复到之前版本的状态。这也是笔者在其他博客上看得比较多的一种解决方法;另外就是使用 DelegatingPasswordEncoder 的 setDefaultPasswordEncoderForMatches 方法指定默认的密码编码器为 NoOpPasswordEncoder。这两种方法孰优孰劣自然不言而喻,官方文档是这么说的:
Reverting to NoOpPasswordEncoder is not considered to be secure. You should instead migrate to using DelegatingPasswordEncoder to support secure password encoding.
恢复到 NoOpPasswordEncoder 被认为是不安全的。您应该转而使用 DelegatingPasswordEncoder 支持安全密码编码。
当然,你也可以将数据库保存的密码都加上一个 {noop} 前缀。这样 DelegatingPasswordEncoder 就知道要使用 NoOpPasswordEncoder了。这确实是一种方法,但没必要。这里我们来看一下前面的两种解决方法的实现:
1 使用NoOpPasswordEncoder取代DelegatingPasswordEncoder
@Bean
public static NoOpPasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
@Bean
public static PasswordEncoder passwordEncoder( ){
DelegatingPasswordEncoder delegatingPasswordEncoder =
(DelegatingPasswordEncoder) PasswordEncoderFactories.createDelegatingPasswordEncoder();
//设置defaultPasswordEncoderForMatches为NoOpPasswordEncoder
delegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(NoOpPasswordEncoder.getInstance());
return delegatingPasswordEncoder;
}