web-dev-qa-db-ja.com

Spring Security 5:ID「null」にマッピングされたPasswordEncoderはありません

私はSpring Boot 1.4.9からSpring Boot 2.0に移行し、Spring Security 5にも移行しています。OAuth 2を介して認証しようとしていますが、このエラーが発生しています:

Java.lang.IllegalArgumentException:id "nullにマップされたPasswordEncoderはありません

Spring Security 5 のドキュメントから、パスワードの保存形式が変更されたことがわかりました。

現在のコードでは、パスワードエンコーダーBeanを次のように作成しています。

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

しかし、それは私に以下のエラーを与えていました:

エンコードされたパスワードはBCryptのように見えません

Spring Security 5 ドキュメントに従ってエンコーダーを更新します:

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

データベースにパスワードが表示されたら、次のように保存されています

{bcrypt}$2a$10$LoV/3z36G86x6Gn101aekuz3q9d7yfBp3jFn7dzNN/AL5630FyUQ

その最初のエラーがなくなり、認証を行おうとすると、以下のエラーが発生します:

Java.lang.IllegalArgumentException:id "nullにマップされたPasswordEncoderはありません

この問題を解決するために、Stackoverflowから以下の質問をすべて試しました。

ここに私のものに似ているが答えられていない質問があります:

注:既に暗号化されたパスワードをデータベースに保存しているため、UserDetailsServiceで再度エンコードする必要はありません。

Spring security 5 ドキュメンテーションでは、以下を使用してこの例外を処理できると提案しました。

DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches(PasswordEncoder)

これが修正である場合、どこに置くべきですか?私はそれを以下のようなPasswordEncoder Beanに入れようとしましたが、うまくいきませんでした:

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

MyWebSecurityクラス

@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
@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);
    }
}

この問題について教えてください。これを修正するのに何時間も費やしましたが、修正できません。

32
Jimmy

ClientDetailsServiceConfigurerを構成するときは、新しい パスワードストレージ形式 もクライアントシークレットに適用する必要があります。

.secret("{noop}secret")
53

同じ問題に直面し、安全なソリューションを必要としない人のために-主にテストとデバッグのために-メモリ内のユーザーはまだ設定できます。

これはただ遊んでいるだけです-現実世界のシナリオはありません。

以下で使用されるアプローチは非推奨です。

これは私がそれを手に入れた場所です:


WebSecurityConfigurerAdapter内に次を追加します。

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

ここでは、明らかに、パスワードはハッシュされますが、メモリ内で利用可能です。


もちろん、PasswordEncoderのような実際のBCryptPasswordEncoderを使用して、正しいIDをパスワードの前に付けることもできます。

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
7
rocksteady

.password("{noop}password")をセキュリティ設定ファイルに追加します。

例えば ​​:

auth.inMemoryAuthentication()
        .withUser("admin").roles("ADMIN").password("{noop}password");
4

Springはパスワードを保存するたびに、bcrypt、scrypt、pbkdf2などのエンコードされたパスワードにエンコーダーのプレフィックスを挿入します。これにより、パスワードをデコードするときに、適切なエンコーダーを使用してデコードできます。エンコードされたパスワードにプレフィックスがない場合、defaultPasswordEncoderForMatchesを使用します。 DelegatingPasswordEncoder.classのmatchesメソッドを表示して、その動作を確認できます。したがって、基本的に次の行でdefaultPasswordEncoderForMatchesを設定する必要があります。

@Bean(name="myPasswordEncoder")
public PasswordEncoder getPasswordEncoder() {
        DelegatingPasswordEncoder delPasswordEncoder=  (DelegatingPasswordEncoder)PasswordEncoderFactories.createDelegatingPasswordEncoder();
        BCryptPasswordEncoder bcryptPasswordEncoder =new BCryptPasswordEncoder();
    delPasswordEncoder.setDefaultPasswordEncoderForMatches(bcryptPasswordEncoder);
    return delPasswordEncoder;      
}

さらに、このエンコーダーにDefaultPasswordEncoderForMatchesを認証プロバイダーにも提供する必要がある場合があります。私は私の設定クラスの以下の行でそれをしました。

@Bean
    @Autowired  
    public DaoAuthenticationProvider getDaoAuthenticationProvider(@Qualifier("myPasswordEncoder") PasswordEncoder passwordEncoder, UserDetailsService userDetailsServiceJDBC) {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        daoAuthenticationProvider.setUserDetailsService(userDetailsServiceJDBC);
        return daoAuthenticationProvider;
    }
1
Vikky

について

エンコードされたパスワードはBCryptのように見えません

私の場合、pwdハッシュは強度4で生成されたため、デフォルトコンストラクター(10)で使用されるBCryptPasswordEncoder強度に不一致がありました。そのため、強度を明示的に設定しました。

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

また、私のSpring Securityバージョンは5.1.6であり、BCryptPasswordEncoderで完全に動作します

0
Bender