Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for the for the id "null" 错误
Oauth2 Client Credentials Flow + Spring Boot2 throwing There is no PasswordEncoder mapped > for the for the id "null" error
我正在升级现有的客户端凭据 Oauth2 以使用 spring boot 2。
授权服务器使用 Base64 编码 (client:secret)
的基本身份验证
我正在使用 RedisTokenStore 来存储令牌。
我正在为新升级的 Oauth2 配置所需的配置而苦恼。我找不到将我指向客户端凭据流程的适当文档。
随着对 Spring 5 安全性的更新,密码编码失败,我得到:-
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped
for the id "null" error
以下是我的配置:-
@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 安全密码编码后,在存储到 redis 存储时,是否还需要对令牌进行编码?
这个错误意味着存储的密码没有以密码类型为前缀。
例如,您的散列密码可能类似于:
a$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
但是,Spring 安全现在期待:
{bcrypt}a$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
是从哪里提取的,但我会从那里开始寻找。
UPDATE:不过,这假定您现有的密码已加密。如果不是,那么您将提供任何合适的编码器:
@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;
}
我正在升级现有的客户端凭据 Oauth2 以使用 spring boot 2。
授权服务器使用 Base64 编码 (client:secret)
的基本身份验证
我正在使用 RedisTokenStore 来存储令牌。
我正在为新升级的 Oauth2 配置所需的配置而苦恼。我找不到将我指向客户端凭据流程的适当文档。
随着对 Spring 5 安全性的更新,密码编码失败,我得到:-
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" error
以下是我的配置:-
@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 安全密码编码后,在存储到 redis 存储时,是否还需要对令牌进行编码?
这个错误意味着存储的密码没有以密码类型为前缀。
例如,您的散列密码可能类似于:
a$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
但是,Spring 安全现在期待:
{bcrypt}a$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
是从哪里提取的,但我会从那里开始寻找。
UPDATE:不过,这假定您现有的密码已加密。如果不是,那么您将提供任何合适的编码器:
@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;
}