Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for t
Posted
技术标签:
【中文标题】Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for the id "null" error【英文标题】:Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for the 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();
AuthorizationServer 和 ResourceServer
@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 存储中时,我还需要对令牌进行编码吗?
【问题讨论】:
【参考方案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的实例呢?以上是关于Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for t的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 client_credentials 从资源服务器访问另一个 oauth2 资源?
spring security oauth2 client_credentials 仅流程
使用 spring gateway 和 Oauth2 配置 Client Credentials Flow
Spring security oauth2 client_credentials认证
如何使用 Spring Security 为 client_credentials 工作流向 Feign 客户端提供 OAuth2 令牌
Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for t