【问题标题】:Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for the for the id "null" errorOauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for the id "null" error
【发布时间】:2019-07-13 20:34:33
【问题描述】:

我正在升级我现有的 Client Credentials Oauth2 以使用 Spring Boot 2。
授权服务器使用基本身份验证,Base64 编码为(client:secret)
我正在使用 RedisTokenStore 来存储令牌。

我正在努力使用新升级进行 Oauth2 配置所需的配置。我找不到指向客户凭证流程的正确文档。
随着 Spring 5 Security 的更新,密码编码失败,我得到:-

java.lang.IllegalArgumentException: 没有映射 PasswordEncoder 对于 id "null" 错误

以下是我的配置:-

@Configuration
public class WebConfiguration extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http.
                        csrf().disable().
                        authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
        }

}

AuthorizationServerResourceServer

@Configuration
@EnableAuthorizationServer
public class Oauth2Configuration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private JedisConnectionFactory jedisConnFactory;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }

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

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        String idForEncode = "bcrypt";
        Map<String, PasswordEncoder> encoderMap = new HashMap<>();
        encoderMap.put(idForEncode, new BCryptPasswordEncoder());
        return new DelegatingPasswordEncoder(idForEncode, encoderMap);
    }

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

    @Configuration
    @EnableResourceServer
    protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/verify_token").authenticated()
                    .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                    .antMatchers(HttpMethod.GET, "/info").permitAll()
                    .antMatchers(HttpMethod.GET, "/health").permitAll();
        }
    }
}

RedisTokenStore

public class Oauth2TokenStore extends RedisTokenStore {
    @Autowired
    private ClientDetailsService clientDetailsService;


    public Oauth2TokenStore(RedisConnectionFactory connectionFactory) {
        super(connectionFactory);
    }

    @Override
    public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
        Object principal = authentication.getPrincipal();

        //Principal is consumer key since we only support client credential flow
        String consumerKey = (String) principal;

        //get client detials
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(consumerKey);


        // Logic to Create JWT
        .
        .
        .
        //Set it to Authentication
        authentication.setDetails(authToken);

       super.storeAccessToken(token, authentication);
    }

    @Override
    public OAuth2Authentication readAuthentication(String token) {
        OAuth2Authentication oAuth2Authentication =  super.readAuthentication(token);
        if (oAuth2Authentication == null) {
            throw new InvalidTokenException("Access token expired");
        }
        return oAuth2Authentication;
    }
}
}

在更新 Spring Security 密码编码后,当我存储在 redis 存储中时,我还需要对令牌进行编码吗?

【问题讨论】:

    标签: java spring spring-boot spring-security spring-security-oauth2


    【解决方案1】:

    此错误表示存储的密码没有以密码类型为前缀。

    例如,您的散列密码可能类似于:

    $2a$10$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
    

    但是,Spring Security 现在正在期待:

    {bcrypt}$2a$10$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
    

    你基本上有two options。首先是使用默认值配置您的DelegatingPasswordEncoder

    @Bean
    public PasswordEncoder passwordEncoder() {
        String idForEncode = "bcrypt";
        BCryptPasswordEncoder bcrypt = new BCryptPasswordEncoder();
        Map<String, PasswordEncoder> encoderMap = 
            Collections.singletonMap(idForEncode, bcrypt);
        DelegatingPasswordEncoder delegating =
            new DelegatingPasswordEncoder(idForEncode, encoderMap);
        delegating.setDefaultPasswordEncoderForMatches(bcrypt);
        return delegating;
    }
    

    或者第二个是批量升级您的密码存储(以{bcrypt}为前缀)。

    我不确定你的 ClientDetailsService 是从哪里来的,但我会开始寻找那里。

    更新:不过,这假设您现有的密码是 bcrypted。如果不是,那么您将提供适当的编码器:

    @Bean
    public PasswordEncoder passwordEncoder() {
        String idForEncode = "bcrypt";
        PasswordEncoder existing = new MyPasswordEncoder();
        PasswordEncoder updated = new BCryptPasswordEncoder();
        Map<String, PasswordEncoder> encoderMap = 
            Collections.singletonMap(idForEncode, updated);
        DelegatingPasswordEncoder delegating =
            new DelegatingPasswordEncoder(idForEncode, encoderMap);
        delegating.setDefaultPasswordEncoderForMatches(existing);
        return delegating;
    }
    

    【讨论】:

    • 感谢您的帮助,clientId 和 secret 是由其他服务生成的,这些服务不属于此应用程序及其面向公众的 API,因此我们需要以明文形式与请求应用程序共享 clientId 和 secret。我认为您是对的,我需要更改存储以附加 {bcrypt},我无法使用您共享的 PasswordEncoder 运行它说Encoded password does not look like BCrypt,我尝试了 NoOpPasswordEncoder.getInstance() 和让它运行起来。
    • 您用于密码的哈希是什么?该错误意味着编码器认为它不是 bcrypt。
    • 我存储的是明文,客户端密钥或客户端密码没有散列,格式为Base64 encode of client:secret
    • 在升级之前它使用的是 PlaintextPasswordEncoder。
    • 那么,为什么不直接返回一个PlaintextPasswordEncoder,OOC的实例呢?
    猜你喜欢
    • 2014-05-18
    • 2020-03-27
    • 2010-11-23
    • 1970-01-01
    • 2018-03-07
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    相关资源
    最近更新 更多