spring-boot 1.5.3 升级到 2.1.7 出现上述错误,查看MAVEN引用信息,引用的spring security版本为5.1.16,其官方文档地址为: https://docs.spring.io/spring...
报错的代码在这:
package org.springframework.security.crypto.password; public class DelegatingPasswordEncoder implements PasswordEncoder { @Override public boolean matches(CharSequence rawPassword, String prefixEncodedPassword) { String id = extractId(prefixEncodedPassword); throw new IllegalArgumentException("There is no PasswordEncoder mapped for the id /"" + id + "/""); } }
根据异常排查,大概的思想是这样:
matches
第2步我给几个例子,帮助学习:
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
获取到的加密类型为 bcrypt
. {noop}password
获取到加密类开地为 noop
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
中获取到的加密类型为 sha256
。 具体的出错的逻辑是这样的:
123456
. 123456
中,获取一个 加密前缀
的东西,获取的值为null。 UnmappedIdPasswordEncoder
matches
算法 spring security支持的列表如下:
String encodingId = "bcrypt"; Map<String, PasswordEncoder> encoders = new HashMap<>(); encoders.put(encodingId, new BCryptPasswordEncoder()); encoders.put("ldap", new org.springframework.security.crypto.password.LdapShaPasswordEncoder()); encoders.put("MD4", new org.springframework.security.crypto.password.Md4PasswordEncoder()); encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5")); encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance()); encoders.put("pbkdf2", new Pbkdf2PasswordEncoder()); encoders.put("scrypt", new SCryptPasswordEncoder()); encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1")); encoders.put("SHA-256", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-256")); encoders.put("sha256", new org.springframework.security.crypto.password.StandardPasswordEncoder());
可以将数据库中密码更新为 {算法前缀}原密码
,来进行升级。新增数据时,也要加入前缀。
可以将数据库中密码更新为 {noop}原密码
,来进行升级。新增数据时,也要加入前缀 noop
。
在升级前,我们是可以如下定义的:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder .userDetailsService(userDetailsService); .passwordEncoder(passwordEncoder()); } private PasswordEncoder passwordEncoder() { return new PasswordEncoder() { @Override public String encode(CharSequence rawPassword) { // 自定义加密算法 return (String) rawPassword; } @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { // 自定义匹配算法 return rawPassword.equals(encodedPassword); } }; } }
升级后,沿用上述写法会报错:
Error:(49, 17) java: 无法访问org.springframework.security.authentication.encoding.PasswordEncoder 找不到org.springframework.security.authentication.encoding.PasswordEncoder的类文件
改写为:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder.authenticationProvider(authProvider()); } private DaoAuthenticationProvider authProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(passwordEncoder()); return authProvider; } private PasswordEncoder passwordEncoder() { return new PasswordEncoder() { @Override public String encode(CharSequence rawPassword) { return (String) rawPassword; } @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { return rawPassword.equals(encodedPassword); } }; } }
注意:直接使用 官方文档推荐
的方法并不生效,猜想原因应该是升级前版本不匹配。官方文档说 If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by exposing a NoOpPasswordEncoder bean.
,我的只所以没有生效,应该是前版本不是4.2.x,在此未做验证。
新项目,在进行密码匹配时,会根据前缀自动调用密码匹配算法。所以,我们只需要在保存用户时,为其调用合适的算法,并设置相应的前缀即可。在此,建立直接调用官方的:
String 加密后的密码 = PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("原密码");