Spring 引导执行器端点安全不适用于自定义 Spring 安全配置
Spring Boot Actuator Endpoints security doesn't work with custom Spring Security Configuration
这是我的 Spring Boot 1.5.1 Actuator application.properties
:
#Spring Boot Actuator
management.contextPath: /actuator
management.security.roles=R_0
这是我的 WebSecurityConfig
:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Value("${logout.success.url}")
private String logoutSuccessUrl;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http
.csrf().ignoringAntMatchers("/v1.0/**", "/logout")
.and()
.authorizeRequests()
.antMatchers("/oauth/authorize").authenticated()
//Anyone can access the urls
.antMatchers("/signin/**").permitAll()
.antMatchers("/v1.0/**").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority("R_0")
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl(logoutSuccessUrl)
.permitAll();
// @formatter:on
}
/**
* Configures the authentication manager bean which processes authentication requests.
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
现在我可以使用具有 R_0
权限的正确用户成功登录我的应用程序,但是当我尝试访问时
http://localhost:8080/api/actuator/beans
我收到以下错误:
There was an unexpected error (type=Forbidden, status=403).
Access is denied. User must have one of the these roles: R_0
如何正确配置 Spring Boot Actuator 以了解正确的 Authentication
?
现在为了让它正常工作,我必须执行以下操作:
management.security.enabled=false
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority("R_0")
是否有机会以正确的方式配置执行器?
已更新
我正在使用 UserDetailsService.UserDetails.Authorities
public Collection<? extends GrantedAuthority> getAuthorities() {
String[] authorities = permissions.stream().map(p -> {
return p.getName();
}).toArray(String[]::new);
return AuthorityUtils.createAuthorityList(authorities);
}
据此link:
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html
By default all sensitive HTTP endpoints are secured such that only
users that have an ACTUATOR role may access them. Security is enforced
using the standard HttpServletRequest.isUserInRole method.
Use the management.security.roles property if you want something
different to ACTUATOR.
所以我认为你所要做的就是在 application.properties 中设置以下 属性。
management.security.roles
例如:
management.security.roles=R_0
要获得 spring 引导执行器端点的授权,您需要具有 ACTUATOR 角色。
参考这个例子Accessing Restricted Actuator Endpoints with Spring Security
您必须为您的 management.security.roles
使用前缀 ROLE_
例如 management.security.roles=ROLE_SOMENAME
才能解决此问题
我是从 Reactive Spring Boot 2.x 应用程序来解决这个问题的,并通过将 WebSecurityConfig.securityWebFilterChain 和 SecurityContextRepository.load 更新为包括 /actuator/** 如下:
public class WebSecurityConfig {
private AuthenticationManager authenticationManager;
private SecurityContextRepository securityContextRepository;
@Autowired
public WebSecurityConfig(AuthenticationManager authenticationManager, SecurityContextRepository securityContextRepository) {
this.authenticationManager = authenticationManager;
this.securityContextRepository = securityContextRepository;
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.exceptionHandling()
.authenticationEntryPoint((swe, e) -> Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
})).accessDeniedHandler((swe, e) -> Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
})).and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.authenticationManager(authenticationManager)
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated()
.and().build();
}
以及更新
@Slf4j
@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {
private AuthenticationManager authenticationManager;
public SecurityContextRepository(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Mono<Void> save(ServerWebExchange swe, SecurityContext sc) {
return Mono.error(new UnsupportedOperationException("Not supported"));
}
@Override
public Mono<SecurityContext> load(ServerWebExchange swe) {
ServerHttpRequest request = swe.getRequest();
if (request.getPath().value().startsWith("/actuator") ) {
return Mono.empty();
}
// other authentication logic here
}
1
1.You can add the following properties
endpoints.health.enabled=true
endpoints.loggers.enabled=true
endpoints.metrics.enabled=true
endpoints.env.enabled=false
endpoints.configprops.enabled=false
endpoints.autoconfig.enabled=false
endpoints.info.enabled=false
management.context-path=/management
2)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ApplicationContextAware {
private static final String ACTUATOR = "ACTUATOR";
private static final String ROLE1 = "USER";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/controllerpath/**")
.hasAnyRole(ROLE1).antMatchers("/loggers/**","/metrics/**","/health/**").hasAnyRole(ACTUATOR).and()
.csrf().disable().headers().frameOptions().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("username-of-app").password("encryptedpassword")
.roles(ROLE1).and().withUser("username-of-management-for-path")
.password("encrypted password").roles(ACTUATOR);
}
}
- 您可以添加以下属性
endpoints.health.enabled=true
endpoints.loggers.enabled=true
endpoints.metrics.enabled=true
endpoints.env.enabled=false
endpoints.configprops.enabled=false
endpoints.autoconfig.enabled=false
endpoints.info.enabled=false
management.context-path=/management
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ApplicationContextAware {
private static final String ACTUATOR = "ACTUATOR";
private static final String ROLE1 = "USER";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/controllerpath/**")
.hasAnyRole(ROLE1).antMatchers("/loggers/**","/metrics/**","/health/**").hasAnyRole(ACTUATOR).and()
.csrf().disable().headers().frameOptions().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("username-of-app").password("encryptedpassword")
.roles(ROLE1).and().withUser("username-of-management-for-path")
.password("encrypted password").roles(ACTUATOR);
}
}
这是我的 Spring Boot 1.5.1 Actuator application.properties
:
#Spring Boot Actuator
management.contextPath: /actuator
management.security.roles=R_0
这是我的 WebSecurityConfig
:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Value("${logout.success.url}")
private String logoutSuccessUrl;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http
.csrf().ignoringAntMatchers("/v1.0/**", "/logout")
.and()
.authorizeRequests()
.antMatchers("/oauth/authorize").authenticated()
//Anyone can access the urls
.antMatchers("/signin/**").permitAll()
.antMatchers("/v1.0/**").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority("R_0")
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl(logoutSuccessUrl)
.permitAll();
// @formatter:on
}
/**
* Configures the authentication manager bean which processes authentication requests.
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
现在我可以使用具有 R_0
权限的正确用户成功登录我的应用程序,但是当我尝试访问时
http://localhost:8080/api/actuator/beans
我收到以下错误:
There was an unexpected error (type=Forbidden, status=403).
Access is denied. User must have one of the these roles: R_0
如何正确配置 Spring Boot Actuator 以了解正确的 Authentication
?
现在为了让它正常工作,我必须执行以下操作:
management.security.enabled=false
.antMatchers("/actuator/health").permitAll()
.antMatchers("/actuator/**").hasAuthority("R_0")
是否有机会以正确的方式配置执行器?
已更新
我正在使用 UserDetailsService.UserDetails.Authorities
public Collection<? extends GrantedAuthority> getAuthorities() {
String[] authorities = permissions.stream().map(p -> {
return p.getName();
}).toArray(String[]::new);
return AuthorityUtils.createAuthorityList(authorities);
}
据此link:
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html
By default all sensitive HTTP endpoints are secured such that only users that have an ACTUATOR role may access them. Security is enforced using the standard HttpServletRequest.isUserInRole method.
Use the management.security.roles property if you want something different to ACTUATOR.
所以我认为你所要做的就是在 application.properties 中设置以下 属性。
management.security.roles
例如:
management.security.roles=R_0
要获得 spring 引导执行器端点的授权,您需要具有 ACTUATOR 角色。 参考这个例子Accessing Restricted Actuator Endpoints with Spring Security
您必须为您的 management.security.roles
使用前缀 ROLE_
例如 management.security.roles=ROLE_SOMENAME
才能解决此问题
我是从 Reactive Spring Boot 2.x 应用程序来解决这个问题的,并通过将 WebSecurityConfig.securityWebFilterChain 和 SecurityContextRepository.load 更新为包括 /actuator/** 如下:
public class WebSecurityConfig {
private AuthenticationManager authenticationManager;
private SecurityContextRepository securityContextRepository;
@Autowired
public WebSecurityConfig(AuthenticationManager authenticationManager, SecurityContextRepository securityContextRepository) {
this.authenticationManager = authenticationManager;
this.securityContextRepository = securityContextRepository;
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http
.exceptionHandling()
.authenticationEntryPoint((swe, e) -> Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
})).accessDeniedHandler((swe, e) -> Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
})).and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.authenticationManager(authenticationManager)
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated()
.and().build();
}
以及更新
@Slf4j
@Component
public class SecurityContextRepository implements ServerSecurityContextRepository {
private AuthenticationManager authenticationManager;
public SecurityContextRepository(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Mono<Void> save(ServerWebExchange swe, SecurityContext sc) {
return Mono.error(new UnsupportedOperationException("Not supported"));
}
@Override
public Mono<SecurityContext> load(ServerWebExchange swe) {
ServerHttpRequest request = swe.getRequest();
if (request.getPath().value().startsWith("/actuator") ) {
return Mono.empty();
}
// other authentication logic here
}
1
1.You can add the following properties
endpoints.health.enabled=true
endpoints.loggers.enabled=true
endpoints.metrics.enabled=true
endpoints.env.enabled=false
endpoints.configprops.enabled=false
endpoints.autoconfig.enabled=false
endpoints.info.enabled=false
management.context-path=/management
2)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ApplicationContextAware {
private static final String ACTUATOR = "ACTUATOR";
private static final String ROLE1 = "USER";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/controllerpath/**")
.hasAnyRole(ROLE1).antMatchers("/loggers/**","/metrics/**","/health/**").hasAnyRole(ACTUATOR).and()
.csrf().disable().headers().frameOptions().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("username-of-app").password("encryptedpassword")
.roles(ROLE1).and().withUser("username-of-management-for-path")
.password("encrypted password").roles(ACTUATOR);
}
}
- 您可以添加以下属性
endpoints.health.enabled=true
endpoints.loggers.enabled=true
endpoints.metrics.enabled=true
endpoints.env.enabled=false
endpoints.configprops.enabled=false
endpoints.autoconfig.enabled=false
endpoints.info.enabled=false
management.context-path=/management
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ApplicationContextAware {
private static final String ACTUATOR = "ACTUATOR";
private static final String ROLE1 = "USER";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/controllerpath/**")
.hasAnyRole(ROLE1).antMatchers("/loggers/**","/metrics/**","/health/**").hasAnyRole(ACTUATOR).and()
.csrf().disable().headers().frameOptions().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("username-of-app").password("encryptedpassword")
.roles(ROLE1).and().withUser("username-of-management-for-path")
.password("encrypted password").roles(ACTUATOR);
}
}