问题
I'm trying to use JDBC Authentication for a REST Controller using Postgresql database. The Configuration class, which manages the authentication is the following one:
@Configuration
@EnableAutoConfiguration
public class JDBCSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select username,password, enabled from users where username=?")
.authoritiesByUsernameQuery("select username, role from user_roles where username=?");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//HTTP Basic authentication
.httpBasic()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/**").hasRole("USER")
.antMatchers(HttpMethod.POST, "/").hasRole("ADMIN")
.and()
.csrf().disable()
.formLogin().disable();
}
}
The Datasource configuration should be ok:
spring.datasource.url=jdbc:postgresql://localhost:5432/springdb
spring.datasource.username=user
spring.datasource.password=password
However, when I try to invoke a method of the Controller, with the User in Role:
@RequestMapping(path= "/", method = RequestMethod.GET, produces = {"application/json"})
public List<Customer> find()
{
return repository.getCustomers();
}
Then it results in the following error:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:244) ~[spring-security-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$LazyPasswordEncoder.matches(AuthenticationConfiguration.java:289) ~[spring-security-config-5.1.6.RELEASE.jar:5.1.6.RELEASE]
Is there anything wrong in the Configuration class? Thanks
回答1:
Issue
- You created the users and password directly in the database. But Spring security expects a prefix in front of your password.
- You are checking for the role like
hasRole("USER")which is equivalent tohasAuthority("ROLE_USER")
Solution:
To fix the password issue, you can use any of the following but not both:
If the password is
testing1, you will have to store the password as{noop}testing1. So update your password in the database accordingly.Define as
NoOpPasswordEncoderbean as your password encoder.
To fix the
authorisationissue:- Prefix your authorities in the database with
ROLE_
- Prefix your authorities in the database with
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
Explanation
- When you don't configure a password encoder, Spring security uses
DelegatingPasswordEncoderas the password encoder. It is actually a list of the following encoders.
public static PasswordEncoder createDelegatingPasswordEncoder() {
String encodingId = "bcrypt";
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put(encodingId, new BCryptPasswordEncoder());
encoders.put("ldap", new LdapShaPasswordEncoder());
encoders.put("MD4", new Md4PasswordEncoder());
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new StandardPasswordEncoder());
encoders.put("argon2", new Argon2PasswordEncoder());
return new DelegatingPasswordEncoder(encodingId, encoders);
}
Since it has a list of password encoders, after retrieving the user and password, it does not know which password encoder was used to encrypt the password.
To solve this problem, spring security expects a prefix to be added to the password. So if the password was created using
BCryptPasswordEncoder, it stores it as{bcrypt}xxx-sdsa-bcrypt-pasa. So on retrieval, it can decide which password encoder was used.
来源:https://stackoverflow.com/questions/62701158/spring-boot-jdbc-authentication-failing