There is no PasswordEncoder mapped for the id "null"

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. 獲取密碼
  2. 獲取默認加密、密碼匹配對象

1.1 獲取獲取的加密類型(加密前綴)
1.2 根據類型找算法
1.3 沒找到算法,則調用默認算法
1.4 默認算法代碼如上,拋出異常:spring

第1.1步我給幾個例子,幫助學習:數據庫

  1. 由密碼{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG獲取到的加密類型爲bcrypt.
  2. 由密碼{noop}password獲取到加密類開地爲noop
  3. 由密碼{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0中獲取到的加密類型爲sha256

具體的出錯的邏輯是這樣的:app

  1. 獲取到了密碼,好比爲123456.
  2. 獲取默認加密、密碼匹配對象:DelegatingPasswordEncoder

1.1 spring嘗試從123456中,獲取一個加密前綴的東西。但獲取的值爲null。
1.2 沒有找到算法,則調用默認算法,此時默認對象爲:UnmappedIdPasswordEncoder
1.3 運行對象UnmappedIdPasswordEncodermatches算法
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("原密碼");
相關文章
相關標籤/搜索