spring-boot 1.5.3 升級到 2.1.7 出現上述錯誤,查看MAVEN引用信息,引用的spring security版本爲5.1.16,其官方文檔地址爲:https://docs.spring.io/spring...html
報錯的代碼在這:java
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 + "\""); } }
根據異常排查,大概的思想是這樣:算法
1.1 獲取獲取的加密類型(加密前綴)
1.2 根據類型找算法
1.3 沒找到算法,則調用默認算法
1.4 默認算法代碼如上,拋出異常:spring
第1.1步我給幾個例子,幫助學習:數據庫
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
獲取到的加密類型爲bcrypt
.{noop}password
獲取到加密類開地爲noop
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
中獲取到的加密類型爲sha256
。具體的出錯的邏輯是這樣的:app
123456
.DelegatingPasswordEncoder
1.1 spring嘗試從123456
中,獲取一個加密前綴
的東西。但獲取的值爲null。
1.2 沒有找到算法,則調用默認算法,此時默認對象爲:UnmappedIdPasswordEncoder
1.3 運行對象UnmappedIdPasswordEncoder
的matches
算法
1.4 拋出異常。ide
spring security支持的列表以下:spring-boot
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());
能夠將數據庫中密碼更新爲{算法前綴}原密碼
,來進行升級。新增數據時,密碼字段也要加入前綴。oop
能夠將數據庫中密碼更新爲{noop}原密碼
,來進行升級。新增數據時,密碼字段也要加入前綴{noop}
。學習
@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,在此未作驗證。
注意:在升級前的定義方法已失效,好比:
@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的類文件
新項目,在進行密碼匹配時,會根據前綴自動調用密碼匹配算法。因此,咱們只須要在保存用戶時,爲其調用合適的算法,並設置相應的前綴便可。在此,創建直接調用官方的:
String 加密後的密碼 = PasswordEncoderFactories.createDelegatingPasswordEncoder().encode("原密碼");