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 шт):

Автор решения: invzbl3

Начиная с версии 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");
    }

См. также примеры на англ..

→ Ссылка