Spring 启动管理服务器无法访问端点(未授权 401)
Spring Boot Admin Server can't get access to endpoints (Unauthorized 401)
我已经配置了我自己的 in-memory 身份验证配置,我的应用程序可以在 Spring 启动管理服务器上自行注册并且服务器获得了正确的凭据,但它仍然从我的应用程序那里得到未经授权的响应.如果我在浏览器中输入凭据,那么它就可以工作了。
@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
在浏览器尝试中获得 header 而在 Spring-Boot-Admin 尝试中BasicAuthenticationFilter
不阅读任何内容 header 并生成匿名用户。
有什么想法吗?
我遇到了类似的问题,并使用以下示例(来自文档)解决了。
@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return instance -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "My Custom Value");
return httpHeaders;
};
}
In case you need to inject custom HTTP headers into the requests made to the monitored application’s actuator endpoints you can easily add a HttpHeadersProvider
解决方法是使用自定义 headers 为 /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;
};
}
}
我已经配置了我自己的 in-memory 身份验证配置,我的应用程序可以在 Spring 启动管理服务器上自行注册并且服务器获得了正确的凭据,但它仍然从我的应用程序那里得到未经授权的响应.如果我在浏览器中输入凭据,那么它就可以工作了。
@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
在浏览器尝试中获得 header 而在 Spring-Boot-Admin 尝试中BasicAuthenticationFilter
不阅读任何内容 header 并生成匿名用户。
有什么想法吗?
我遇到了类似的问题,并使用以下示例(来自文档)解决了。
@Bean
public HttpHeadersProvider customHttpHeadersProvider() {
return instance -> {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "My Custom Value");
return httpHeaders;
};
}
In case you need to inject custom HTTP headers into the requests made to the monitored application’s actuator endpoints you can easily add a
HttpHeadersProvider
解决方法是使用自定义 headers 为 /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;
};
}
}