如何用Spring Security自定义Spring Boot /actuator/loggers/*端点的访问权限
问题描述
我有一个Spring Boot应用,暴露了Spring Actuator等端点,需要通过自定义逻辑保护部分端点的访问权限。现有Spring Security配置代码如下:
fun filterChain(http: HttpSecurity): SecurityFilterChain? { val letRecoAuthenticationFilter = LetRecoAuthenticationFilter(authenticationManager, authenticationContextService) letRecoAuthenticationFilter.setAuthenticationFailureHandler(LetRecoAuthenticationFailureHandler()) letRecoAuthenticationFilter.setAuthenticationSuccessHandler(successHandler()) http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .exceptionHandling() .and() .addFilterBefore(letRecoAuthenticationFilter, AnonymousAuthenticationFilter::class.java) .authorizeHttpRequests { authorizeRequests -> authorizeRequests .requestMatchers(AntPathRequestMatcher("/swagger*")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/form")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/connection")).permitAll() .requestMatchers(AntPathRequestMatcher("/feature-toggles")).permitAll() .requestMatchers(AntPathRequestMatcher("/feature-toggles*")).permitAll() .requestMatchers(AntPathRequestMatcher("/example*")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/list")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/configuration")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/actuator/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/admin")).permitAll() .requestMatchers(AntPathRequestMatcher("/admin/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/actuator/loggers/*")).access(AuthorizationManagers.allOf(hasRight())) .anyRequest().authenticated() } .csrf() .disable() .formLogin().disable() .httpBasic().disable() .logout().disable() return http.build() }
我希望当自定义方法hasRight()返回true时,允许访问/actuator/loggers/*端点,该方法代码如下:
private fun hasRight(): Boolean { // Implement your logic to call the service.hasright method return service.hasRight() }
请问如何在Spring Boot和Spring Security中实现这一需求?
解决方案
核心问题分析
现有代码存在两个关键问题:
- 规则顺序错误:
/actuator/*的permitAll()规则写在/actuator/loggers/*的权限检查规则前面,Spring Security会优先匹配更宽泛的路径,导致/actuator/loggers/*的权限规则永远不会生效。 - 权限校验方式错误:
hasRight()直接返回Boolean值,这会在SecurityFilterChain初始化时就执行一次,而不是在每次请求时动态校验。access()方法需要的是AuthorizationManager<RequestAuthorizationContext>类型的参数,而非静态布尔值。
正确实现方式
方式一:自定义AuthorizationManager
创建一个自定义的AuthorizationManager,注入你的服务并实现动态权限校验逻辑:
@Component class CustomLoggerAuthorizationManager(private val yourService: YourService) : AuthorizationManager<RequestAuthorizationContext> { override fun check(authentication: Authentication?, context: RequestAuthorizationContext): AuthorizationDecision { // 可根据请求上下文、认证信息执行自定义校验 val hasPermission = yourService.hasRight() return AuthorizationDecision(hasPermission) } }
在Security配置中注入该Manager,并调整规则顺序(具体路径放在宽泛路径前面):
@Autowired private lateinit var customLoggerAuthorizationManager: CustomLoggerAuthorizationManager fun filterChain(http: HttpSecurity): SecurityFilterChain? { val letRecoAuthenticationFilter = LetRecoAuthenticationFilter(authenticationManager, authenticationContextService) letRecoAuthenticationFilter.setAuthenticationFailureHandler(LetRecoAuthenticationFailureHandler()) letRecoAuthenticationFilter.setAuthenticationSuccessHandler(successHandler()) http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .exceptionHandling() .and() .addFilterBefore(letRecoAuthenticationFilter, AnonymousAuthenticationFilter::class.java) .authorizeHttpRequests { authorizeRequests -> authorizeRequests // 先配置具体路径规则 .requestMatchers(AntPathRequestMatcher("/actuator/loggers/*")).access(customLoggerAuthorizationManager) // 再配置宽泛路径规则 .requestMatchers(AntPathRequestMatcher("/swagger*")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/form")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/connection")).permitAll() .requestMatchers(AntPathRequestMatcher("/feature-toggles")).permitAll() .requestMatchers(AntPathRequestMatcher("/feature-toggles*")).permitAll() .requestMatchers(AntPathRequestMatcher("/example*")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/list")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/configuration")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/actuator/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/admin")).permitAll() .requestMatchers(AntPathRequestMatcher("/admin/*")).permitAll() .anyRequest().authenticated() } .csrf() .disable() .formLogin().disable() .httpBasic().disable() .logout().disable() return http.build() }
方式二:使用SpEL表达式
如果你的服务是Spring管理的Bean,可直接通过SpEL表达式调用其方法,同时调整规则顺序:
fun filterChain(http: HttpSecurity): SecurityFilterChain? { val letRecoAuthenticationFilter = LetRecoAuthenticationFilter(authenticationManager, authenticationContextService) letRecoAuthenticationFilter.setAuthenticationFailureHandler(LetRecoAuthenticationFailureHandler()) letRecoAuthenticationFilter.setAuthenticationSuccessHandler(successHandler()) http .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .exceptionHandling() .and() .addFilterBefore(letRecoAuthenticationFilter, AnonymousAuthenticationFilter::class.java) .authorizeHttpRequests { authorizeRequests -> authorizeRequests .requestMatchers(AntPathRequestMatcher("/actuator/loggers/*")).access("@yourService.hasRight()") .requestMatchers(AntPathRequestMatcher("/swagger*")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/form")).permitAll() .requestMatchers(AntPathRequestMatcher("/login/connection")).permitAll() .requestMatchers(AntPathRequestMatcher("/feature-toggles")).permitAll() .requestMatchers(AntPathRequestMatcher("/feature-toggles*")).permitAll() .requestMatchers(AntPathRequestMatcher("/example*")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/list")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/configuration")).permitAll() .requestMatchers(AntPathRequestMatcher("/cache/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/actuator/*")).permitAll() .requestMatchers(AntPathRequestMatcher("/admin")).permitAll() .requestMatchers(AntPathRequestMatcher("/admin/*")).permitAll() .anyRequest().authenticated() } .csrf() .disable() .formLogin().disable() .httpBasic().disable() .logout().disable() return http.build() }
注:@yourService中的yourService是Spring容器中该服务Bean的名称(无自定义名称时默认是类名首字母小写)。
关键注意点
- 规则顺序:Spring Security权限规则按顺序匹配,必须把更具体的路径规则放在宽泛路径规则前面,否则具体规则会被覆盖。
- 动态校验:确保权限校验逻辑在每次请求时执行,而非初始化阶段,才能根据实时状态判断是否允许访问。
内容的提问来源于stack exchange,提问作者abdel
相关产品推荐
相关产品推荐

