spring-security 使用多个Web安全配置器适配器的Spring安全oauth2Login和httpBasic

ocebsuys  于 2022-11-11  发布在  Spring
关注(0)|答案(1)|浏览(241)

我需要公开受Okta登录保护的API(oauth2 Login),且除了公开执行器端点之外,执行器端点还需要使用基本身份验证进行保护。我已经基于相应的requestMatchers创建了两个WebSecurityConfigurerAdapter,其中ActuatorSecurityConfiguration的顺序为HIGHEST_PRECEDENCE。问题是当我点击执行器端点时,它正在进入oauth2身份验证流而不是httpBasic,我希望获得基本身份验证弹出窗口,但它却重定向到oauth登录屏幕。看起来okta-spring-boot-starter自动配置正在忽略任何其他配置,并强制所有已定义的WebSecurityConfigurerAdapter进行oauth2 Login,而不考虑顺序和请求匹配器?

@EnableWebSecurity
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/monitoring/**").and()
                .httpBasic()
                .and()
                .authorizeRequests().antMatchers("/monitoring/health").permitAll()
                .and()
                .authorizeRequests().anyRequest().hasRole("ACTUATOR")
                .and().csrf().disable()
                ;
    }

和OktaSecurity配置:

@EnableWebSecurity
@Configuration
@Order(Ordered.LOWEST_PRECEDENCE)
public class OktaSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
                .requestMatchers().antMatchers("/rest/**").and()
                .oauth2Login()
...

MVN依赖树:

+- com.okta.spring:okta-spring-boot-starter:jar:2.1.5:compile
[INFO] |  +- com.okta.spring:okta-spring-security-oauth2:jar:2.1.5:compile
[INFO] |  |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  |  +- com.okta.commons:okta-config-check:jar:1.3.0:compile
[INFO] |  |  +- com.okta.commons:okta-commons-lang:jar:1.3.0:compile
[INFO] |  |  +- org.springframework.security:spring-security-oauth2-jose:jar:5.6.1:compile
[INFO] |  |  \- org.springframework.security:spring-security-oauth2-resource-server:jar:5.6.1:compile
[INFO] |  \- com.okta.spring:okta-spring-sdk:jar:2.1.5:compile
...
+- org.springframework.boot:spring-boot-starter-security:jar:2.6.1:compile
[INFO] |  +- org.springframework:spring-aop:jar:5.3.15:compile
[INFO] |  +- org.springframework.security:spring-security-config:jar:5.6.1:compile
[INFO] |  |  \- org.springframework.security:spring-security-core:jar:5.6.1:compile
[INFO] |  \- org.springframework.security:spring-security-web:jar:5.6.1:compile
...
[INFO] |  +- org.springframework.boot:spring-boot-starter-actuator:jar:2.6.1:compile
[INFO] |  |  \- org.springframework.boot:spring-boot-actuator-autoconfigure:jar:2.6.1:compile
[INFO] |  |     \- org.springframework.boot:spring-boot-actuator:jar:2.6.1:compile
vcudknz3

vcudknz31#

该问题是错误的错误处理,因为“/monitoring/**”请求中缺少身份验证基本标头,它将进入LoginUrlAuthenticationEntryPoint,并相应地重定向到oauth登录屏幕。通过为ActuatorSecurityConfiguration添加authenticationEntryPoint以在浏览器上响应“WWW-Authenticate”标头和弹出窗口,解决了该问题。

@EnableWebSecurity
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ActuatorSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/monitoring/**").and()
                .httpBasic()
                .and().exceptionHandling().authenticationEntryPoint(actuatorBasicAuthenticationEntryPoint())
                .and().authorizeRequests().antMatchers("/monitoring/health").permitAll()
                .and().authorizeRequests().anyRequest().hasRole("ACTUATOR")
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and().csrf().disable()
                ;
    }

    @Bean
    AuthenticationEntryPoint actuatorBasicAuthenticationEntryPoint() {
        return new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
                response.addHeader("WWW-Authenticate", "Basic realm=\"" + "realmName" + "\"");
                response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
            }
        };
    }

相关问题