【问题标题】:Spring Security BadCredentialsExceptionSpring Security BadCredentialsException
【发布时间】:2018-11-14 16:16:12
【问题描述】:

我正在关注this Baeldung tutorial,但我看不到任何差异(可能预生成的登录页面模板除外),但在尝试使用硬编码的用户/密码组合登录时,我仍然得到BadCredentialsException,我已经确认在数据库中并且那里的密码是加密的。

这是我的代码,如果需要更多,请告诉我:

安全配置:

@Component
@EnableWebSecurity
@SuppressWarnings("unused")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/css/**").permitAll()
                .antMatchers("/error").permitAll()
                .antMatchers("/action/**").hasRole("USER")
                .antMatchers("/action_template/**").hasRole("ADMIN")
                .and()
                .formLogin()
                .loginPage("/login").failureUrl("/login-error");
    }

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

    @Bean
    public DaoAuthenticationProvider authProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();

        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());

        return authProvider;
    }

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

}

我的用户详细信息服务:

@Service
@Transactional
@SuppressWarnings("unused")
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

        User user = userRepository.findByEmail(email);

        if (user == null) {
            throw new UsernameNotFoundException(
                    "No user found with username: " + email);
        }

        final List<GrantedAuthority> authorities = new ArrayList<>();
        user.getRoles().forEach((r) -> authorities.add(new SimpleGrantedAuthority(r)));

        return  new org.springframework.security.core.userdetails.User(
                user.getEmail(),
                user.getPassword().toLowerCase(),
                true,
                true,
                true,
                true,
                authorities
        );
    }

}

编辑:

这是堆栈跟踪

2018-11-14 13:52:05.785 DEBUG 2100 --- [nio-8090-exec-5] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials

org.springframework.security.authentication.BadCredentialsException: Bad credentials
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:93)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

我还编辑了我的 SecurityConfig 并添加了 .antMatchers("/error").permitAll(),但没有帮助

编辑 2:

这里是Github repo,它应该提供更多的洞察力。 我不知道如何进一步诊断...

【问题讨论】:

    标签: java spring spring-mvc spring-boot spring-security


    【解决方案1】:

    Spring Boot 可以自动获取/创建所有必要的 bean,因此您可以像这样简化 SecurityConfig(如果没有定义这样的 bean,它将找到您的 UserDetailsS​​ervice 并创建一个默认的 DaoAuthenticationProvider):

    @Component
    @EnableWebSecurity
    @SuppressWarnings("unused")
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/css/**").permitAll()
                    .antMatchers("/error").permitAll()
                    .antMatchers("/action/**").hasRole("USER")
                    .antMatchers("/action_template/**").hasRole("ADMIN")
                    .and()
                    .formLogin()
                    .loginPage("/login").failureUrl("/login-error");
        }
    
    }
    

    还在不同的配置类中定义 passwordEncoder bean(但我不确定是否还需要):

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

    【讨论】:

    • 我已经修好了;)谢谢你的提示,我会测试你所说的关于UserDetailsService的内容!
    【解决方案2】:

    我……很困惑。 我发现了这个问题。我不知道为什么我认为可以保留它,也不知道为什么教程中有它,但即使密码是“密码”,user.getPassword().toLowerCase() 也是小写 BCrypt 哈希,而不是实际密码. 删除 .toLowerCase() 修复它。

    【讨论】:

    • 大声笑,我没注意到。您仍然应该考虑按照我在回答中的建议简化配置。
    【解决方案3】:

    问题看起来与您注册密码编码的方式有关。尝试像这样注册它:

    @Autowired
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
         auth
              .userDetailsService(userDetailsService)
              .passwordEncoder(bCryptPasswordEncoder);
    }
    

    【讨论】:

    • 你把那个放在哪里了?
    • configure(HttpSecurity http),在.antMatchers("/css/**").permitAll()之后
    • 还没有成功...我应该公开 Github repo 并链接它吗?
    猜你喜欢
    • 2012-05-19
    • 2015-11-12
    • 2013-10-06
    • 2017-07-11
    • 2016-03-02
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 2018-02-05
    相关资源
    最近更新 更多