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

Spring Security OAuth2与Basic认证配置问题:Prometheus访问Actuator报BadCredential异常排查

这个问题我之前也碰到过!核心原因是你的服务作为OAuth2资源服务器,默认的Spring Security过滤器链是用来处理OAuth2令牌认证的,而你给Prometheus配置的是HTTP Basic认证——这俩默认不兼容,所以当你给/actuator/**加上角色权限控制时,Prometheus的Basic Auth凭证根本不被识别,自然就抛出BadCredential异常了。

下面给你两种可行的解决方案,我推荐第一种,逻辑更清晰:

方案一:为Actuator端点单独配置Basic Auth安全链

因为Actuator的监控端点不需要走业务的OAuth2认证,我们可以把它从ResourceServer的拦截范围中排除,单独给它配置一套Basic Auth的安全规则。

步骤1:修改ResourceServerConfiguration,排除Actuator端点

修改你的ResourceServerConfiguration,让/actuator/**的请求不经过OAuth2资源服务器的认证,交给专门的配置处理:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                // 把Actuator端点交给专门的安全配置处理
                .antMatchers("/actuator/**").permitAll()
                .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
                .antMatchers("/**").authenticated();
    }
}

步骤2:创建Actuator专属的安全配置类

新建一个配置类,专门处理Actuator的Basic Auth认证,注意要设置@Order(1)让它的优先级高于ResourceServer(ResourceServer默认Order是3):

@Configuration
@Order(1)
public class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${spring.security.name}")
    private String actuatorUsername;

    @Value("${spring.security.password}")
    private String actuatorPassword;

    @Value("${spring.security.roles}")
    private String actuatorRole;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                // 只拦截Actuator相关请求
                .antMatcher("/actuator/**")
                .authorizeRequests()
                // 要求必须拥有指定角色
                .anyRequest().hasRole(actuatorRole)
                // 启用HTTP Basic认证
                .and()
                .httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置内存用户认证(生产环境建议用数据库存储,配合密码编码器)
        auth.inMemoryAuthentication()
                .withUser(actuatorUsername)
                // 注意:Spring Security 5+要求必须指定密码编码器,{noop}表示明文(生产环境禁用!)
                .password("{noop}" + actuatorPassword)
                .roles(actuatorRole);
    }

    // 生产环境请使用这个密码编码器,替换上面的{noop}
    // @Bean
    // public PasswordEncoder passwordEncoder() {
    //     return new BCryptPasswordEncoder();
    // }
}

注意事项

  • 生产环境绝对不能用{noop}明文密码!要启用上面注释的BCryptPasswordEncoder,然后把application.yml里的密码换成BCrypt加密后的字符串。
  • @Order(1)是关键:确保Actuator的安全配置先于ResourceServer生效,这样/actuator/**的请求会优先走这套规则。

方案二:在ResourceServer中同时支持OAuth2和Basic Auth(可选)

如果你不想拆分配置,也可以在ResourceServer中添加Basic Auth的认证提供者,让系统同时支持OAuth2令牌和Basic Auth。不过这种方式逻辑稍复杂,不如第一种直观:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Value("${spring.security.name}")
    private String actuatorUsername;

    @Value("${spring.security.password}")
    private String actuatorPassword;

    @Value("${spring.security.roles}")
    private String actuatorRole;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security", "/swagger-ui.html", "/webjars/**", "/swagger-resources/configuration/ui", "/swagger-resources/configuration/security").permitAll()
                .antMatchers("/actuator/**").hasRole(actuatorRole)
                .antMatchers("/**").authenticated()
                .and()
                // 添加Basic Auth过滤器
                .addFilterBefore(basicAuthFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    private BasicAuthenticationFilter basicAuthFilter() throws Exception {
        return new BasicAuthenticationFilter(authenticationManager());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 先保留原有的OAuth2认证逻辑(如果有的话)
        super.configure(auth);
        // 添加Actuator的Basic Auth用户
        auth.inMemoryAuthentication()
                .withUser(actuatorUsername)
                .password("{noop}" + actuatorPassword)
                .roles(actuatorRole);
    }
}

这种方式需要确保Basic Auth过滤器被添加到正确的位置,同时处理好和OAuth2过滤器的优先级,所以更推荐第一种方案。

最后检查你的Prometheus配置,目前的basic_auth配置是正确的,只要用户名密码和我们配置的一致,就能正常拉取指标了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 07:32:38