具有匿名访问的 Spring Boot Security 预身份验证场景

2024-03-28

我有一个 Spring Boot (1.5.6) 应用程序正在使用“预认证 https://docs.spring.io/spring-security/site/docs/current/reference/html/preauth.html来自 Spring Security 的身份验证场景 (SiteMinder)。

我需要匿名公开执行器“健康”端点,这意味着对该端点的请求将not通过 SiteMinder,因此 SM_USER 标头将不会出现在 HTTP 请求标头中。

我面临的问题是,无论我如何尝试配置“健康”端点,框架都会抛出一个错误org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException因为当请求不通过 SiteMinder 时,预期的标头(“SM_USER”)不存在。

这是我原来的安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .authorizeRequests().antMatchers("/cars/**", "/dealers/**")
                .hasAnyRole("CLIENT", "ADMIN")
            .and()
                .authorizeRequests().antMatchers("/health")
                .permitAll()
            .and()
                .authorizeRequests().anyRequest().denyAll()
            .and()
                .addFilter(requestHeaderAuthenticationFilter())
                .csrf().disable();
    }

    @Bean
    public Filter requestHeaderAuthenticationFilter() throws Exception {
        RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManager());
        return filter;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(preAuthProvider());
    }

    @Bean
    public AuthenticationProvider preAuthProvider() {
        PreAuthenticatedAuthenticationProvider authManager = new PreAuthenticatedAuthenticationProvider();
        authManager.setPreAuthenticatedUserDetailsService(preAuthUserDetailsService());
        return authManager;
    }

    @Bean
    public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthUserDetailsService() {
        return new UserDetailsByNameServiceWrapper<>(inMemoryUserDetails());
    }

    @Bean
    public UserDetailsService inMemoryUserDetails() {
        return new InMemoryUserDetailsManager(getUserSource().getUsers());
    }

    @Bean
    public UserHolder getUserHolder() {
        return new UserHolderSpringSecurityImple();
    }

    @Bean
    @ConfigurationProperties
    public UserSource getUserSource() {
        return new UserSource();
    }

我尝试用几种不同的方法排除 /health 端点,但没有成功。

我尝试过的事情:

配置健康端点以进行匿名访问而不是允许所有:

http
   .authorizeRequests().antMatchers("/health")
   .anonymous()

配置 WebSecurity 以忽略运行状况端点:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/health");
}

关闭安全功能all执行器端点(不知道,但我正在抓住救命稻草):

management.security.enabled=false

查看日志,问题似乎是 RequestHeaderAuthenticationFilter 正在注册为顶层过滤器而不是现有的过滤器安全过滤链:

.s.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'webRequestLoggingFilter' to: [/*]
o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestHeaderAuthenticationFilter' to: [/*]

根据我的理解,因为RequestHeaderAuthenticationFilter延伸AbstractPreAuthenticatedProcessingFilter,框架知道在链中插入过滤器的位置,这就是为什么我不修改 addFilterBefore或添加过滤器After变体。也许我应该是?有人知道明确插入过滤器的正确位置吗? (我认为在 Spring Security 的早期版本中删除了显式指定过滤器顺序的需要)

我知道我可以配置RequestHeaderAuthenticationFilter这样,如果标头不存在,它就不会抛出异常,但如果可能的话,我想保留它。

我发现这个帖子似乎与我的问题相似,但不幸的是那里也没有答案。spring-boot-security-pre 身份验证-with-permissed-resources-still-authenticator https://stackoverflow.com/questions/45971407/spring-boot-security-preauthentication-with-permitted-resources-still-authenti

任何帮助将不胜感激! 谢谢!


问题确实在于 RequestHeaderAuthenticationFilter 正在注册both作为顶级过滤器(不需要)and also在 Spring Security FilterChain 中(需要)。

“双重注册”的原因是因为 Spring Boot 会注册任何FilterBeans 会自动与 Servlet 容器一起使用。

为了防止“自动注册”,我只需要定义一个FilterRegistrationBean像这样:

@Bean
public FilterRegistrationBean registration(RequestHeaderAuthenticationFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

Docs: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-disable-registration-of-a-servlet-or-filter https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-disable-registration-of-a-servlet-or-filter

替代/更简单的解决方案:只是不标记RequestHeaderAuthenticationFilter类作为@Bean这很好,因为该特定过滤器不需要任何 DI。通过不标记过滤器@Bean,引导不会尝试自动注册它,这消除了定义 FilterRegistrationBean 的需要。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有匿名访问的 Spring Boot Security 预身份验证场景 的相关文章

随机推荐