Spring-Boot с CustomAuthenticationProvider и CustomPasswordEncoder - PullRequest
0 голосов
/ 20 марта 2019

Мне не ясно, как приклеить мой CustomPasswordEncoder к процессу аутентификации при весенней загрузке. В конфигурации я определяю, что при весенней загрузке должен использоваться мой CustomAuthenticationProvider с моим UserDetailsService и моим CustomPasswordEncoder

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;


    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {

        builder.authenticationProvider(customAuthenticationProvider)
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder encoder = new CustomPasswordEncoder();
        return encoder;
    }       
}

Мой CustomPasswordEncoder будет кодировать в значение md5 (я знаю, что это небезопасно, но это устаревшая база данных)

@Component
public class CustomPasswordEncoder implements PasswordEncoder{

    @Override
    public String encode(CharSequence rawPassword) {
return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());

    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {

        return rawPassword.toString().equals(encodedPassword);
    }
}

В CustomAuthtenticationProvider будет выполнена проверка подлинности. Поставленный пароль будет закодирован с помощью passwordEncoder.encode (). Пользователь будет извлечен из базы данных, затем я снова использую passwordEncoder для сопоставления. Если совпадение прошло успешно, будет создан объект аутентификации.

    @Component
    public class CustomAuthenticationProvider implements AuthenticationProvider {

        @Autowired
        private UserServiceImpl userService;
        @Autowired
        private CustomPasswordEncoder passwordEncoder;



        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            System.out.println("authentication = [" + authentication + "]");
            String name = authentication.getName();
            Object credentials = authentication.getCredentials();

            String password = credentials.toString();
            //why is this necessary isnt it called automatically?
            String passwordEncoded = passwordEncoder.encode((CharSequence) credentials);
            Optional<UserEntity> userOptional = userService.findByUsername(name);

            if (userOptional.isPresent() && passwordEncoder.matches(passwordEncoded, userOptional.get().getPassword())) {
                List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
                grantedAuthorities.add(new SimpleGrantedAuthority(userOptional.get().getRoles().toString()));
                Authentication auth = new
                        UsernamePasswordAuthenticationToken(name, password, grantedAuthorities);
                return auth;
            }
            else{
                throw new BadCredentialsException("Authentication failed for " + name);
            }
        }

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

Это правильный подход? Я думал, что CustomPasswordEncoder будет использоваться «автоматически» или только в том случае, если вы используете один из предоставленных провайдеров аутентификации, таких как jdbcAuthenticationProvider. Может быть, кто-то может объяснить порядок событий процесса аутентификации. Я провел некоторое исследование в сети, но все еще не могу понять это подробно.

1 Ответ

1 голос
/ 20 марта 2019

Сначала, как вы можете видеть из метода matches, он проверяет необработанный пароль (введенный пользователем) с помощью закодированного пароля.Таким образом, код для кодирования принадлежит методу matches вместо того, что вы используете сейчас.

public class CustomPasswordEncoder implements PasswordEncoder{

    @Override
    public String encode(CharSequence rawPassword) {
      return DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        String rawEncoded = encode(rawPassword);
        return Objects.equals(rawEncoded, encodedPassword);
    }
}

Теперь вы можете удалить строку / шаг кодирования из кода.

Однако вам на самом деле не нужен пользовательский AuthenticationProvider, так как он обычно требуется только при добавлении другого механизма аутентификации, такого как LDAP или OAuth.

Вам нужен адаптер для UserService к UserDetailsService и используйте его.Я предполагаю, что UserDetailsServiceImpl делает именно это.Если нет, вы можете использовать что-то вроде кода ниже.

public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserService delegate;

    public UserDetailsServiceAdapter(UserService delegate) {
        this.delegate=delegate;
    }

    public UserDetails loadUserByUsername(String username) {
       reutrn userService.findByUsername(name)
                 .map(this::toUserDetails).orElseThrow(() -> new UsernameNotFoundException("Unknown user " + username);
    }

    private UserDetails toUserDetails(User user) {
        Set<GrantedAuthority> authorities = new HashSet<>();
        user.getRoles().forEach(r -> authorities.add(new SimpleGrantedAuthority(r));
         return new UserDetails(user.getUsername(), user.getPassword(), authorities);
    }
}

Теперь вы можете использовать PasswordEncoder и этот адаптер в конфигурации, и вам не понадобится ваш пользовательский AuthenticationProvider.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {

        builder.userDetailsService(userDetailsService)
               .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        PasswordEncoder encoder = new CustomPasswordEncoder();
        return encoder;
    }       
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...