Spring Security 5: Il n'y a pas de PasswordEncoder mappé pour l'id " null"

je suis en train de passer de la botte à ressort 1.4.9 à la botte à ressort 2.0 et aussi à la sécurité à ressort 5 et j'essaie de faire l'authentification via OAuth 2. Mais je reçois cette erreur:

de java.lang.IllegalArgumentException: il n'y a pas de PasswordEncoder cartographié pour l'id "null

de la documentation de Spring Security 5 , j'apprends que le format de stockage du mot de passe est modifié.

dans mon code actuel j'ai créé mon encodeur de mot de passe bean comme:

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

mais il me donnait d'erreur ci-dessous:

le mot de passe encodé ne ressemble pas à BCrypt

donc je mets à jour l'encodeur selon le Spring Security 5 document à:

@Bean
public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

maintenant si je peux voir mot de passe dans la base de données il est stockage en tant que

{bcrypt}a$LoV/3z36G86x6Gn101aekuz3q9d7yfBp3jFn7dzNN/AL5630FyUQ

Avec cette 1ère erreur disparu et maintenant quand j'essaie de faire de l'authentification, je suis d'erreur ci-dessous:

de java.lang.IllegalArgumentException: il n'y a pas de PasswordEncoder cartographié pour l'id "null

pour résoudre ce problème j'ai essayé toutes les questions ci-dessous de Stackoverflow:

  • Passwordencoder Pour Bottes De Printemps Erreur

  • Printemps Oauth2. L'encodeur de mot de passe n'est pas défini dans Dao-AuthenticationProvider

Voici une question semblable à la mienne mais sans réponse:

  • Printemps De Sécurité 5 - Migration Des Mots De Passe

NOTE: je stocke déjà un mot de passe crypté dans la base de données donc non besoin d'encoder à nouveau dans UserDetailsService .

dans la documentation Spring security 5 ils ont suggéré que vous pouvez gérer cette exception en utilisant:

DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches (PasswordEncoder)

si c'est la solution, Où dois-je la mettre? J'ai essayé de le mettre dans PasswordEncoder bean comme ci-dessous mais il ne fonctionnait pas:

DelegatingPasswordEncoder def = new DelegatingPasswordEncoder(idForEncode, encoders);
def.setDefaultPasswordEncoderForMatches(passwordEncoder);

MyWebSecurity classe

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {

        web
                .ignoring()
                .antMatchers(HttpMethod.OPTIONS)
                .antMatchers("/api/user/add");
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

Myoauth2 Configuration

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;


    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

    @Bean
    public DefaultAccessTokenConverter accessTokenConverter() {
        return new DefaultAccessTokenConverter();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        endpoints
                .tokenStore(tokenStore())
                .tokenEnhancer(tokenEnhancer())
                .accessTokenConverter(accessTokenConverter())
                .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                .inMemory()
                .withClient("test")
                .scopes("read", "write")
                .authorities(Roles.ADMIN.name(), Roles.USER.name())
                .authorizedGrantTypes("password", "refresh_token")
                .secret("secret")
                .accessTokenValiditySeconds(1800);
    }
}

guidez-moi avec ce numéro. J'ai passer des heures à résoudre ce problème, mais pas en mesure de corriger.

15
demandé sur dur 2018-04-04 17:51:52

2 réponses

lorsque vous configurez le ClientDetailsServiceConfigurer , vous devez également appliquer le nouveau format de stockage de mot de passe au secret client.

.secret("{noop}secret")
26
répondu Edwin Diaz-Mendez 2018-04-15 09:33:00

pour toute personne confrontée au même problème et n'ayant pas besoin d'une solution sécurisée - pour le test et le débogage principalement - en mémoire les utilisateurs peuvent encore être configurés.

Ceci est juste pour jouer autour - pas de scénario du monde réel.

l'approche utilisée ci-dessous est dépréciée.

C'est de là que je l'ai obtenu:


dans votre WebSecurityConfigurerAdapter ajouter le suivant:

@SuppressWarnings("deprecation")
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}

ici, évidemment, les mots de passe sont hachés, mais sont toujours disponibles en mémoire.


bien sûr, vous pouvez aussi utiliser un vrai PasswordEncoder comme BCryptPasswordEncoder et préfixer le mot de passe avec le bon id:

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
3
répondu rocksteady 2018-04-16 07:04:32