Spring Security: PasswordEncoder mapped for the id “null”
Использую Spring 2.2.5.RELEASE
При отправке GET запроса с именем пользователя и паролем, получаю ошибку вида:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:250) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$LazyPasswordEncoder.matches(AuthenticationConfiguration.java:312) ~[spring-security-config-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:90) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:195) ~[spring-security-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
Конфигурация написана таким образом:
@Configuration
public class SpringSecurityConfiguration_InMemory extends WebSecurityConfigurerAdapter {
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().
withUser("user").password("password")
.roles("USER");
auth.
inMemoryAuthentication().withUser("admin").
password("password")
.roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/user/")
.hasRole("USER")
.antMatchers(HttpMethod.POST, "/api/user/")
.hasRole("USER")
.antMatchers(HttpMethod.PUT, "/api/user/**")
.hasRole("USER")
.antMatchers(HttpMethod.DELETE, "/api/user/**")
.hasRole("ADMIN")
.and()
.csrf()
.disable();
}
}
Как можно исправить ошибку?
Ответы (1 шт):
Начиная с версии Spring Security 5.0 используется DelegatingPasswordEncoder вместо NoOpPasswordEncoder. Также альтернативным вариантом может быть BCryptPasswordEncoder, но лучше DelegatingPasswordEncoder.
Для решения данной ошибки можно, используя NoOpPasswordEncoder в методе inMemoryAuthentication, добавить {noop} (сокр. от No Operation) по принципу:
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().
withUser("user").password("{noop}password")
.roles("USER");
auth.
inMemoryAuthentication().withUser("admin").
password("{noop}password")
.roles("USER", "ADMIN");
}
Но это небезопасно, т.к. NoOpPasswordEncoder является устаревшим:
Deprecated. This PasswordEncoder is not secure. Instead use an adaptive one way function like BCryptPasswordEncoder, Pbkdf2PasswordEncoder, or SCryptPasswordEncoder. Even better use DelegatingPasswordEncoder which supports password upgrades.
Аналогично можно воспользоваться BCryptPasswordEncoder:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password"))
.roles("USER");
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder().encode("password"))
.roles("USER", "ADMIN");
}
Или же DelegatingPasswordEncoder:
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password"))
.roles("USER");
auth.inMemoryAuthentication()
.withUser("admin").password(encoder.encode("password"))
.roles("USER", "ADMIN");
}