You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security OIDC中BCrypt密码匹配失败问题求助

问题:BCrypt密码匹配失败,认证报错Bad credentials

数据库中password字段长度为255字符,已正确持久化到数据库。已确认BCrypt版本与强度匹配,调试未发现本地变量异常,但passwordEncoder.matches()方法始终返回false,多方搜索仍未解决。

错误日志

2024-09-07T19:46:13.867+03:00 TRACE 2672624 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : Invoking UsernamePasswordAuthenticationFilter (6/13)
2024-09-07T19:46:13.868+03:00 TRACE 2672624 --- [nio-8080-exec-4] o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/2)
2024-09-07T19:46:13.871+03:00  WARN 2672624 --- [nio-8080-exec-4] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt
2024-09-07T19:46:13.871+03:00 DEBUG 2672624 --- [nio-8080-exec-4] o.s.s.a.dao.DaoAuthenticationProvider    : Failed to authenticate since password does not match stored value
2024-09-07T19:46:13.871+03:00 TRACE 2672624 --- [nio-8080-exec-4] o.s.s.authentication.ProviderManager     : Authenticating request with DaoAuthenticationProvider (1/1)
2024-09-07T19:46:13.873+03:00  WARN 2672624 --- [nio-8080-exec-4] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt
2024-09-07T19:46:13.873+03:00 DEBUG 2672624 --- [nio-8080-exec-4] o.s.s.a.dao.DaoAuthenticationProvider    : Failed to authenticate since password does not match stored value
2024-09-07T19:46:13.873+03:00 TRACE 2672624 --- [nio-8080-exec-4] w.a.UsernamePasswordAuthenticationFilter : Failed to process authentication request

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

相关代码

UserDetailsService实现

@Service
public class SecurityUserService implements UserDetailsService {

    final private JdbcTemplate jdbcTemplate;

    public SecurityUserService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        String sql = "SELECT * FROM user WHERE username = ?";
        return jdbcTemplate.query(sql, new SecurityUserMapper(), username).getFirst();
    }
}

SecurityUserMapper实现

public class SecurityUserMapper implements RowMapper<SecurityUser> {

    @Override
    public SecurityUser mapRow(ResultSet rs, int rowNum) throws SQLException {
        SecurityUser user = new SecurityUser();
        user.setUsername(rs.getString("username"));
        user.setPassword(rs.getString("password"));
        return user;
    }

}

AuthServerConfig配置

@Configuration
public class AuthServerConfig {

    private final RsaKeyProperties rsaKeys;
    private UserDetailsService userDetailsService = new SecurityUserService(new JdbcTemplate());

    public AuthServerConfig(RsaKeyProperties rsaKeys, UserDetailsService userDetailsService) {
        this.rsaKeys = rsaKeys;
        this.userDetailsService = userDetailsService;
    }

    @Bean
    @Order(0)
    public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {

        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());
        http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        http.exceptionHandling((exceptions) -> exceptions.defaultAuthenticationEntryPointFor(
                new LoginUrlAuthenticationEntryPoint("/login"),
                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)));
        return http.build();
    }

    @Bean
    @Order(1)
    public SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable());
        http.userDetailsService(userDetailsService);
        http.formLogin(Customizer.withDefaults());
        http.httpBasic(Customizer.withDefaults()); // new line
        http.logout(logout -> logout.logoutUrl("/login?logout"));
        http.authorizeHttpRequests(request -> {
            request.dispatcherTypeMatchers(
                    DispatcherType.FORWARD,
                    DispatcherType.ERROR).permitAll();
            request.requestMatchers("/oauth2/token").permitAll();
            request.anyRequest().authenticated();
        });
        return http.build();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(BCryptVersion.$2A);
    }

    @Bean
    JwtEncoder jwtEncoder() {
        JWK jwk = new RSAKey.Builder(rsaKeys.publicKey()).privateKey(rsaKeys.privateKey()).build();
        JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
        return new NimbusJwtEncoder(jwks);
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(rsaKeys.publicKey()).build();
    }

    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder().build();
    }

    @Bean
    RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
        return new JdbcRegisteredClientRepository(jdbcTemplate);
    }
}

补充信息

为测试登录请求,已实现默认Basic认证,请求截图如下:
Insomnia POST请求截图

内容的提问来源于stack exchange,提问作者andr1337228

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:07:35