Как создать условный AuthenticationProvider в Spring-Security?

До сих пор я хранил свое имя пользователя и зашифрованные пароли в базе данных.

Мой пользовательский UserDetailsService ищет пользователя в базе данных. Пароли хранятся в зашифрованном виде, поэтому здесь применяется BCryptPasswordEncoder.

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
}

Проблема: теперь мне нужно добавить дополнительный источник аутентификации, который обслуживает пароли незашифрованный (я не могу это контролировать). Таким образом, если аутентифицированный пользователь не может быть найден в моей базе данных, я хочу проверить дополнительный источник с незашифрованными паролями. Но как я могу отключить кодировщик BCrypt для этих случаев?

В данный момент я не на своей машине разработки, но я считаю, что есть составной кодировщик паролей специально для этого варианта использования (онлайн-миграция). Вы можете распознать пароли Bcrypt по префиксу.

chrylis -cautiouslyoptimistic- 30.07.2019 13:43

@chrylis, так что мне пришлось бы ставить перед всеми моими закодированными паролями в базе данных префикс {bcrypt}, это правильно? А потом просто полагаться на весенние значения по умолчанию?

membersound 30.07.2019 13:48

Пароли Bcrypt уже имеют префикс $2a$.

chrylis -cautiouslyoptimistic- 30.07.2019 13:53

Я попробовал это, не устанавливая свой собственный кодировщик паролей, поэтому загружается DelegatingPasswordEncoder по умолчанию: префикс с {bcrypt} работает и делегирует кодировщику brcypt. Простое использование простого закодированного pw, начинающегося с $2a$, не работает! Может я что-то не так делаю?

membersound 30.07.2019 13:56

Я удивлен и не совсем уверен, что происходит, но если это сработает для вас, отлично!

chrylis -cautiouslyoptimistic- 30.07.2019 13:57
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
756
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

несколько дней назад я также столкнулся с этой проблемой, мои устаревшие системные данные зашифрованы в MD5, но новый пароль для сохранения системы в BCrypt

для решения этой проблемы я пишу некоторый собственный код и использую AuthenticationProvider вместо UserDetailsService

здесь я вырезаю свой код для вашей помощи

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    LoginDao loginDao;

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

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        List<GrantedAuthority> grantList = new ArrayList<>();
        String name = authentication.getName();
        String password = ((String) authentication.getCredentials()).trim();
        try {
            UserModel user = loginDao.getUser(name);
            if (user != null) {
                if (passwordEncoder().matches(password, user.getLoginPass())) {
                //  System.out.println("------Good new & Strong password -----");
                    GrantedAuthority authority = new SimpleGrantedAuthority(user.getAuthotype().toString());
                    grantList.add(authority);
                }else if (password.equals(user.getLoginPass())) {//here i have md5 checker service , i remove it for your help 
                //  System.out.println("------old password! should be change it-----"); 
                    GrantedAuthority authority = new SimpleGrantedAuthority(user.getAuthotype().toString());
                    grantList.add(authority);
                }else {
                    throw new BadCredentialsException("Please enter a valid username and password.");
                }
                    return new UsernamePasswordAuthenticationToken(user, password, grantList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BadCredentialsException("Please enter a valid username and password.");
        }
        throw new BadCredentialsException("Please enter a valid username and password.");
    }

    @Override
    public boolean supports(Class<? extends Object> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

и измените свой код класса SecurityConfiguration

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

Согласно текущим документам (https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/password/DelegatingPasswordEncoder.html), Мне просто нужно удалить мой установщик .passwordEncoder(), чтобы весной полагаться на новую функцию делегирования пароля по умолчанию.

Затем добавьте ко всем моим паролям префикс {bcrypt} для моих паролей к базе данных и {noop} для моих новых паролей в виде открытого текста.

Ответ принят как подходящий

Вы можете настроить несколько поставщиков аутентификации, как показано ниже. Каждый провайдер аутентификации тестируется по порядку, и тот, который прошел проверку первым, предоставляет аутентифицированные данные, а остальные пропускаются. Подобный вариант использования реализован аналогичным образом, когда вы должны сначала пройти аутентификацию через базу данных, а затем сервер LDAP (или наоборот) также обрабатывается аналогичным образом.

@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProviderWithEncryptedUser);
    auth.authenticationProvider(authenticationProviderWithNonEncryptedUser);

}

Это замечательно. Я объединил этот подход, используя два DaoAuthenticationProvider, у каждого из которых есть свой UserDetailsService. Принимая во внимание, что один — мой старый сервис bcrypt, а другой — новый незашифрованный сервис.

membersound 30.07.2019 15:26

Другие вопросы по теме