Spring security - 编码的密码给了我错误的凭据

标签 spring spring-security

我正在使用 Spring security 并使用编码器对密码进行编码。

因此,在我的 Spring Security 配置中,我已自动连接 PasswordEncoderpasswordEncoder() 并将其添加到 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

我在数据库中的密码字段是 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;
    }

}

最佳答案

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一旦 user.getPassword() 将被抛出BCrypt 哈希和的格式不正确。

密码编码器可以这样注册:

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

protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            
     auth
          .userDetailsService(userDetailsService)
          .passwordEncoder(bCryptPasswordEncoder);
}

这就是它的工作原理。

关于Spring security - 编码的密码给了我错误的凭据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43007763/

相关文章:

未找到 Spring 配置

java - 带有敏感信息的 Spring Boot 外部配置不起作用

java - @EnableBatchProcessing放置在哪里?

ios - 我的 Xcode 应用程序图标项目中出现齿轮图标,我无法再运行它

java - Spring:使用 Spring Security 为执行器端点配置安全性

java - 在 Spring Security 中处理自定义异常

javascript - Chrome、Safari 和 Firefox 上的 CORS POST 请求失败

Spring Security 5自定义failureForwardUrl

spring - Keycloak Spring 安全客户端凭据授予

spring - 过滤器 null 中的 LocaleResolver 仍显示它已 Autowiring ! Spring MVC 3.1.1/Spring 安全 3.1.0