Я обновляю свои существующие клиентские учетные данные Oauth2, чтобы использовать весеннюю загрузку 2.
Сервер авторизации использует базовую аутентификацию с кодировкой Base64(client:secret)
.
Я использую RedisTokenStore для хранения токенов.
У меня возникают проблемы с конфигурацией, необходимой для конфигурации Oauth2 с новым обновлением. Я не смог найти надлежащую документацию, которая указывает мне на поток учетных данных клиента.
С обновлениями Spring 5 Security кодировка пароля не работает, я получаю :-
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();
}
}
Сервер авторизации и Ресурссервер
@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;
}
}
}
Также нужно ли мне кодировать токен, когда я сохраняю его в магазине Redis после обновления весенней кодировки пароля безопасности?




Эта ошибка означает, что сохраненный пароль не имеет префикса с типом пароля.
Например, ваши хешированные пароли могут выглядеть примерно так:
$2a$10$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
Но теперь Spring Security ожидает:
{bcrypt}$2a$10$betZ1XaM8rTUQHwWS.cyIeTKJySBfZsmC3AYxYjwa4fHtr6i/.9oG
У вас в основном есть два варианта. Во-первых, настроить 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 тянет, но я бы начал искать там.
ОБНОВИТЬ: это предполагает, однако, что ваши существующие пароли зашифрованы. Если это не так, вы должны предоставить любой соответствующий кодировщик:
@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;
}
Какой хэш вы используете для своих паролей? Ошибка означает, что кодировщик считает, что это не bcrypt.
Я храню его в виде открытого текста, в ключе клиента или секрете клиента нет хэша, формат Base64 encode of client:secret
до обновления он использовал PlaintextPasswordEncoder.
Итак, почему бы просто не вернуть экземпляр PlaintextPasswordEncoder, OOC?
Я не могу, так как это больше не часть весны 5.
спасибо за вашу помощь, clientId и секрет генерируются другой службой, которая не является частью этого приложения, и это общедоступный API, поэтому нам нужно поделиться clientId и секретом в открытом тексте с запрашивающим приложением. Я думаю, вы правы, мне нужно изменить хранилище, чтобы добавить {bcrypt}, я не смог запустить его с помощью PasswordEncoder, которым вы поделились, он говорит
Encoded password does not look like BCrypt, я попробовал NoOpPasswordEncoder.getInstance() и запустил его.