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("原密码");