Spring Boot Admin Server无法访问端点(未经授权的401)

时间:2019-10-11 13:30:01

标签: spring-boot spring-boot-admin

我已经配置了自己的内存中身份验证配置,并且我的应用程序可以在Spring Boot Admin Server上注册自己,并且服务器获得了正确的凭据,但是仍然会从我的应用程序获得未经授权的响应。如果我在浏览器中输入凭据,那么它将起作用。

@Configuration
@Order(2)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {
  @Value("${spring.boot.admin.client.instance.metadata.user.name:actuator}")
  private String actuatorName;
  @Value("${spring.boot.admin.client.instance.metadata.user.password:secret}")
  private String actuatorPassword;

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser(actuatorName).password("{noop}" + actuatorPassword).authorities("ACTUATOR");
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
    http
            .antMatcher("/actuator/**")
            .authorizeRequests()
            .anyRequest().hasAuthority("ACTUATOR")
            .and()
            .httpBasic();
  }
}

spring-boot-admin-dashboard

有效的浏览器请求与导致401的Spring-Boot-Admin请求之间的区别在于,“ BasicAuthenticationFilter”在brwoser尝试中获得了标头,但是在Spring-Boot-Admin尝试中,“ BasicAuthenticationFilter”却不读任何标头,并且导致匿名用户。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我遇到了类似的问题,并使用下面的示例(来自文档)解决了该问题。

@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
    return  instance -> {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "My Custom Value");
        return httpHeaders;
    };
}
  

如果您需要将自定义HTTP标头注入到对受监视应用程序的执行器端点的请求中,则可以轻松添加HttpHeadersProvider

参考: Injecting Custom HTTP Headers

答案 1 :(得分:0)

一种解决方法是,使用自定义标头为/ actuator / **路径构建自己的过滤器,如下所示:

在应用程序方面:

@Configuration
@Order(2)
public class ActuatorSecurity extends WebSecurityConfigurerAdapter {

  public static String name = "actuator-admin";
  public static String pw = "actuator-pw";

  public static String headerName = "ACTUATOR_HEADER_NAME";
  public static String headerPw = "ACTUATOR_HEADER_PW";


  protected String getActuatorFilterUrl() {
    return "/actuator/" + "**";
  }

  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .cors()
            .and()
            // we don't need CSRF because our token is invulnerable
            .csrf().disable()
            // All urls must be authenticated (filter for token always fires (/**)
            .antMatcher(getActuatorFilterUrl())

            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS).permitAll()
            .antMatchers(getActuatorFilterUrl()).authenticated()

            .and()
            .addFilterBefore(new ActuatorSecurityFilter(getActuatorFilterUrl(), name, pw, headerName, headerPw),
                    UsernamePasswordAuthenticationFilter.class)
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  }
}

public class ActuatorSecurityFilter extends AbstractAuthenticationProcessingFilter {

  private String name;
  private String pw;

  private String headerName;
  private String headerPw;

  public ActuatorSecurityFilter(String filterUrl, String name, String pw, String headerName, String headerPw) {
    super(filterUrl);
    this.name = name;
    this.pw = pw;

    this.headerName = headerName;
    this.headerPw = headerPw;
  }

  @Override
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
    final String name = request.getHeader(headerName);
    final String pw = request.getHeader(headerPw);

    if (name.equals(this.name) && pw.equals(this.pw)) {
      return new Authentication() {
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
          return new ArrayList<>();
        }

        @Override
        public Object getCredentials() {
          return null;
        }

        @Override
        public Object getDetails() {
          return null;
        }

        @Override
        public Object getPrincipal() {
          return null;
        }

        @Override
        public boolean isAuthenticated() {
          return true;
        }

        @Override
        public void setAuthenticated(boolean b) throws IllegalArgumentException {

        }

        @Override
        public String getName() {
          return null;
        }
      };
    }
    throw new IllegalStateException("name or pw wrong");
  }

  @Override
  protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
          throws IOException, ServletException {

    SecurityContextHolder.getContext().setAuthentication(authResult);

    // As this authentication is in HTTP header, after success we need to continue the request normally
    // and return the response as if the resource was not secured at all
    chain.doFilter(request, response);
  }
}

在Spring-Admin方面:

@Configuration
public class CUstomHeaderConf {

  @Bean
  public HttpHeadersProvider customHttpHeadersProvider() {
    return  instance -> {
      HttpHeaders httpHeaders = new HttpHeaders();
      httpHeaders.add("ACTUATOR_HEADER_NAME", "actuator-admin");
      httpHeaders.add("ACTUATOR_HEADER_PW", "actuator-pw");
      return httpHeaders;
    };
  }
}