Spring安全密码为我提供了Bad Credentials

时间:2017-03-24 19:34:48

标签: spring spring-security

我使用Spring安全性并使用编码器对密码进行编码。

所以,在我的Spring Security Config中,我自动连接 PasswordEncoder passwordEncoder()并将其添加到DaoAuthenticationProvider,这是我的Spring Security配置

   package it.besmart.easyparking.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.servlet.support.RequestDataValueProcessor;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    CustomSuccessHandler customSuccessHandler;

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    DataSource dataSource;

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(authenticationProvider());
    }

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

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/", "/home", "/user/**").permitAll()
                .antMatchers("/spots/**", "/parks/**", "/floors/**", "/lights/**", "/sensors/**", "/illumination/**",
                        "/occupation/**", "/movement/**", "/map/**", "/include/**")
                .access("hasRole('USER') or hasRole('ADMIN') or hasRole('PARK')").antMatchers("/admin/**")
                .access("hasRole('ADMIN') and hasRole('PARK')").antMatchers("/updatePassword")
                .hasAuthority("CHANGE_PASSWORD_PRIVILEGE").

                and().formLogin().loginPage("/login").successHandler(customSuccessHandler)
                .failureHandler(customAuthenticationFailureHandler).usernameParameter("email")
                .passwordParameter("password").and().rememberMe().rememberMeParameter("remember-me")
                .tokenRepository(persistentTokenRepository()).tokenValiditySeconds(86400).and().csrf().and()
                .exceptionHandling().accessDeniedPage("/Access_Denied");

    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepositoryImpl = new JdbcTokenRepositoryImpl();
        tokenRepositoryImpl.setDataSource(dataSource);
        return tokenRepositoryImpl;
    }

    @Bean
    public RequestDataValueProcessor requestDataValueProcessor() {
        return new CsrfRequestDataValueProcessor();
    }

}

当我将数据从我的DTO传递到模型时,我只需执行以下操作

user.setPassword(passwordEncoder.encode(accountDTO.getPassword()));

在我的数据库中,我看到了编码的密码,例如 $ 2a $ 10 $ vVCWjKltOiYO0nPYT1qYI.z4TSk2QJqViDOqRfmoB6BAgldF4vAmm

但是当我尝试登录时,我正在

org.springframework.security.authentication.BadCredentialsException: Bad credentials

当我看到日志时,我发现了这个

o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt

我在DB中的密码字段是varchar(100)所以我认为有足够的空间来存储它... 如果我用解码的密码更改数据库中的编码密码,我可以登录...

这是我的CustoUserDetailsS​​ervice

@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    UserRepository repository;

    private final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

        boolean accountNonExpired = true;
        boolean credentialsNonExpired = true;
        boolean accountNonLocked = true;
        try {
            User user = repository.findByEmail(email);
            if (user == null) {
                throw new UsernameNotFoundException("No user found with username: " + email);
            }
            logger.debug("user: " + user.toString());
            return new org.springframework.security.core.userdetails.User(user.getEmail(),

                    user.getPassword(), user.isEnabled(), accountNonExpired, credentialsNonExpired, accountNonLocked,
                    getAuthorities(user));
        } catch (Exception e) {
            throw new RuntimeException(e);

        }
    }

    private List<GrantedAuthority> getAuthorities(User user) {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getUserProfile().getType()));

        // System.out.print("authorities :"+authorities);
        return authorities;
    }

}

2 个答案:

答案 0 :(得分:1)

异常确实来自UserDetailsService.loadUserByUsername()位置的return方法,因为错误的实例化User对象没有收到相应字段的编码密码。

它应该是这样的:

...

public UserDetails loadUserByUsername(String username) 
                                      throws UsernameNotFoundException {

    UserEntity user = userRepository.findByUsername(username);

    if (user == null)
       throw new UsernameNotFoundException("Bad credentials");

    return new User(
        user.getUsername(), 
        user.getPassword(), // shall to be the already BCrypt-encrypted password
        getAuthorities());
}

一旦org.springframework.security.authentication.BadCredentialsException: Bad credentials形成良好的BCrypt hashsum,user.getPassword()将被抛出。

密码编码器应该像这样注册:

@Autowired
public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
}

protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

     auth
          .userDetailsService(userDetailsService)
          .passwordEncoder(bCryptPasswordEncoder);
}

检查出来

答案 1 :(得分:0)

PasswordEncoder应该像这样设置:

@Bean
public PasswordEncoder passwordEncoder() {
  return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

此外,您还需要为用户和客户端使用passwordEncoder。

您可以查看此存储库https://github.com/dzinot/spring-boot-2-oauth2-authorization-jwt

它使用 Spring Boot 2 ,JWT令牌,用户和客户端存储在数据库中。