Spring Boot + Auth0:在Azure App Service上,健康检查端点返回401,但在本地可以正常工作,尽管该路径已从SecurityFilterChain中排除

前端开发 2026-07-11

我在一个使用OAuth2资源服务器的Spring Boot应用中实现Auth0的认证。

一切在本地工作正常,但在部署到Azure App Service之后,无法在没有Bearer令牌的情况下访问我的健康检查端点。无论如何都会收到 401 Unauthorized,尽管该端点在我的 SecurityFilterChain 中已经被显式排除在认证之外。

预期行为

/health/actuator/health 应该无需认证即可访问。

实际行为

在部署到 Azure App Service 之后,访问:

GET /health
GET /actuator/health

返回:

401 Unauthorized

然而,同样的端点在本地无需Bearer令牌即可工作。

进一步排查

我还尝试将健康端点移入一个 单独的 SecurityFilterChain,该端点对 /health/actuator/health 允许所有请求,但部署到Azure之后,行为仍然相同。

application.yml

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: <issuer-uri>
          audiences: <audience>

auth0:
  audience: <audience>
  issuerURI: <issuer-uri>

AudienceValidator

public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
    private final String audience;

    public AudienceValidator(String audience) {
        this.audience = audience;
    }

    public OAuth2TokenValidatorResult validate(Jwt jwt) {
        if (jwt.getAudience().contains(audience)) {
            return OAuth2TokenValidatorResult.success();
        }
        OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
        return OAuth2TokenValidatorResult.failure(error);
    }
}

安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Value("${auth0.issuerURI}")
    private String issuerUri;

    @Value("${auth0.audience}")
    private String audience;

    @Value("${allowed-cors-origins}")
    private String allowedOrigins;

    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/health", "/actuator/health").permitAll()
                        .requestMatchers("/v1/admin/**").hasRole("ADMIN")
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt -> jwt
                            .jwtAuthenticationConverter(jwtAuthenticationConverter())
                        )
                )
                .csrf(AbstractHttpConfigurer::disable);

        return http.build();
    }

    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthoritiesClaimName("https://Placeholder.com/roles");
        grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

        JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
        converter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return converter;
    }
}

环境

  • Spring Boot 4.1.0-M2
  • Spring Security 4.1.0-M2
  • Auth0
  • Azure App Service
  • Java 21

其他观察

  • 同一个构建在本地可以工作。
  • issuer-uriaudience、和 placeholder.com 配置正确。
  • 健康端点应通过 .requestMatchers("/health", "/actuator/health").permitAll() 排除。

问题

为什么这些端点在仅部署到Azure App Service之后仍然返回 401 Unauthorized,尽管它们已在 SecurityFilterChain 中被显式排除?

是否存在某些Azure专用的因素(例如反向代理头、路径重写、actuator配置,或安全过滤器的执行顺序)会导致这种行为?

服务器日志

2026-03-11T21:45:52.630Z DEBUG 93 --- [           main] 
o.s.s.web.DefaultSecurityFilterChain : Will secure any request with filters:
DisableEncodeUrlFilter,
WebAsyncManagerIntegrationFilter,
SecurityContextHolderFilter,
HeaderWriterFilter,
CsrfFilter,
LogoutFilter,
OAuth2ProtectedResourceMetadataFilter,
BearerTokenAuthenticationFilter,
AuthenticationFilter,
RequestCacheAwareFilter,
SecurityContextHolderAwareRequestFilter,
AnonymousAuthenticationFilter,
ExceptionTranslationFilter,
AuthorizationFilter

2026-03-11T21:46:11.586Z DEBUG 93 --- [p-nio-80-exec-3]
o.s.security.web.FilterChainProxy : Securing GET /actuator/health

2026-03-11T21:46:11.614Z DEBUG 93 --- [p-nio-80-exec-3]
o.s.s.w.a.AnonymousAuthenticationFilter :
Set SecurityContextHolder to anonymous SecurityContext

2026-03-11T21:46:11.655Z DEBUG 93 --- [p-nio-80-exec-3]
o.s.s.w.s.HttpSessionRequestCache :
Saved request https://example.azurewebsites.net/actuator/health?continue to session

2026-03-11T21:46:59.637Z DEBUG 93 --- [p-nio-80-exec-4]
o.s.security.web.FilterChainProxy : Securing GET /actuator/health

2026-03-11T21:46:59.649Z DEBUG 93 --- [p-nio-80-exec-4]
o.s.s.w.a.AnonymousAuthenticationFilter :
Set SecurityContextHolder to anonymous SecurityContext

2026-03-11T21:46:59.667Z DEBUG 93 --- [p-nio-80-exec-4]
o.s.s.w.s.HttpSessionRequestCache :
Saved request https://example.azurewebsites.net/actuator/health?continue to session

请求/响应

GET /actuator/health HTTP/1.1
User-Agent: PostmanRuntime/7.51.1
Accept: */*
Postman-Token: f3002c0e-d920-4130-afe2-1df8e872d649
Host: example.westeurope-01.azurewebsites.net
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: JSESSIONID=95A12962B2439D240BBDF0E17775F57B

HTTP/1.1 401 Unauthorized
Content-Length: 0
Date: Thu, 12 Mar 2026 08:14:32 GMT
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: 0
Pragma: no-cache
WWW-Authenticate: Bearer resource_metadata="https://example.westeurope-01.azurewebsites.net/.well-known/oauth-protected-resource"
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY

解决方案

当从curl调用的响应中查看时,我们可以看到以下内容:

WWW-Authenticate: Bearer resource_metadata="https://example.westeurope-01.azurewebsites.net/.well-known/oauth-protected-resource"

这里的这一行告诉我们,是Azure本身在阻止请求,而不是Spring Boot应用。.well-known/oauth-protected-resource 遵循 RFC9728 的规定,基本上通过元数据告知我们该API需要Bearer令牌。

当Spring拒绝令牌时,响应头通常是:

WWW-Authenticate: Bearer error="invalid_token", error_description="..."

在这种情况下,由于发现日志中甚至没有打印任何请求,我相当确定开启了Azure Easy Auth之类的东西。

我并不能确切地说如何禁用它,因为我无法访问相关的Azure,而且Azure的 API改动频繁。但据了解,它被称为Easy Auth,可以在 Azure App Service Authentication and Authorization 中了解。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章