You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring OAuth2授权服务器OpenID配置请求返回401未授权问题排查

问题描述

已部署一个授权服务器,另有依赖spring-security-oauth2-client组件的服务用于从该授权服务器获取令牌。授权服务器仅通过YAML配置客户端信息,无自定义配置类。测试环境中,服务启动时请求http://oauthz:8080/.well-known/openid-configuration和http://oauthz:8080/.well-known/oauth-authorization-server获取OpenID配置时,持续返回401 UNAUTHORIZED响应;但本地使用http://localhost:8080访问授权服务器则无此问题,需调整授权服务器配置解决该错误。

授权服务器YAML配置

logging:
  level:
    org.springframework.security: trace

spring:
  security:
    oauth2:
      authorizationserver:
        client:
          oidc-client:
            registration:
              client-id: "rdocelec"
              client-secret: "{noop}xxx"
              client-authentication-methods:
                - "client_secret_basic"
              authorization-grant-types:
                - "client_credentials"
              scopes:
                - "api"
            require-authorization-consent: true

请求日志

HTTP GET http://oauthz:8080/.well-known/openid-configuration
Accept=[application/json, application/cbor, application/*+json]
sun.net.www.MessageHeader@20395afe5 pairs: {GET /.well-known/openid-configuration HTTP/1.1: null}{Accept: application/json, application/cbor, application/*+json}{User-Agent: Java/11.0.21}{Host: oauthz:8080}{Connection: keep-alive}
sun.net.www.MessageHeader@4b1339bf16 pairs: {null: HTTP/1.1 401}{Vary: Origin}{Vary: Access-Control-Request-Method}{Vary: Access-Control-Request-Headers}{WWW-Authenticate: Basic realm="Realm"}{X-Content-Type-Options: nosniff}{X-XSS-Protection: 0}{Cache-Control: no-cache, no-store, max-age=0, must-revalidate}{Pragma: no-cache}{Expires: 0}{X-Frame-Options: DENY}{WWW-Authenticate: Basic realm="Realm"}{Content-Length: 0}{Date: Thu, 16 Nov 2023 10:34:41 GMT}{Keep-Alive: timeout=60}{Connection: keep-alive}
Response 401 UNAUTHORIZED
HTTP GET http://oauthz:8080/.well-known/openid-configuration
Accept=[application/json, application/cbor, application/*+json]
sun.net.www.MessageHeader@451f08ea5 pairs: {GET /.well-known/openid-configuration HTTP/1.1: null}{Accept: application/json, application/cbor, application/*+json}{User-Agent: Java/11.0.21}{Host: oauthz:8080}{Connection: keep-alive}
sun.net.www.MessageHeader@dcf495c16 pairs: {null: HTTP/1.1 401}{Vary: Origin}{Vary: Access-Control-Request-Method}{Vary: Access-Control-Request-Headers}{WWW-Authenticate: Basic realm="Realm"}{X-Content-Type-Options: nosniff}{X-XSS-Protection: 0}{Cache-Control: no-cache, no-store, max-age=0, must-revalidate}{Pragma: no-cache}{Expires: 0}{X-Frame-Options: DENY}{WWW-Authenticate: Basic realm="Realm"}{Content-Length: 0}{Date: Thu, 16 Nov 2023 10:34:41 GMT}{Keep-Alive: timeout=60}{Connection: keep-alive}
Response 401 UNAUTHORIZED
HTTP GET http://oauthz:8080/.well-known/oauth-authorization-server
Accept=[application/json, application/cbor, application/*+json]
sun.net.www.MessageHeader@60610a2b5 pairs: {GET /.well-known/oauth-authorization-server HTTP/1.1: null}{Accept: application/json, application/cbor, application/*+json}{User-Agent: Java/11.0.21}{Host: oauthz:8080}{Connection: keep-alive}
sun.net.www.MessageHeader@420dee8216 pairs: {null: HTTP/1.1 401}{Vary: Origin}{Vary: Access-Control-Request-Method}{Vary: Access-Control-Request-Headers}{WWW-Authenticate: Basic realm="Realm"}{X-Content-Type-Options: nosniff}{X-XSS-Protection: 0}{Cache-Control: no-cache, no-store, max-age=0, must-revalidate}{Pragma: no-cache}{Expires: 0}{X-Frame-Options: DENY}{WWW-Authenticate: Basic realm="Realm"}{Content-Length: 0}{Date: Thu, 16 Nov 2023 10:34:41 GMT}{Keep-Alive: timeout=60}{Connection: keep-alive}
Response 401 UNAUTHORIZED

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>net.gencat.transversal.espaidoc</groupId>
    <artifactId>oautz</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oauthz</name>
    <description>Oauth Authorization server</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
    <finalName>oauthz</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

解决方案

原因分析

从日志的WWW-Authenticate: Basic realm="Realm"可以看出,请求被Spring Security的默认认证拦截器拦截,说明授权服务器的元数据端点(/.well-known/**)未被配置为允许匿名访问。虽然Spring Authorization Server的自动配置应该默认开放这些端点,但可能因环境差异或配置优先级问题导致规则未生效。

解决步骤

方法1:通过YAML配置开放端点

在授权服务器的application.yml中添加Spring Security的授权规则,明确允许匿名访问元数据端点:

spring:
  security:
    authorization:
      authorize-requests:
        authorize:
          "/.well-known/**": permitAll
          "/oauth2/jwks": permitAll
          "/oauth2/authorize": authenticated
          "/oauth2/token": authenticated
          "/oauth2/revoke": authenticated
          "/oauth2/introspect": authenticated
          "/**": denyAll

方法2:添加自定义Security配置类

创建一个Spring Security配置类,显式配置端点的访问权限:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                // 开放元数据和JWKS端点
                .requestMatchers("/.well-known/**", "/oauth2/jwks").permitAll()
                // 其他授权服务器端点需认证
                .requestMatchers("/oauth2/authorize", "/oauth2/token", "/oauth2/revoke", "/oauth2/introspect").authenticated()
                // 其余端点拒绝访问
                .anyRequest().denyAll()
            );
        return http.build();
    }
}

验证修改

重启授权服务器后,测试环境的客户端服务应能正常获取OpenID配置,不再返回401错误。

内容的提问来源于stack exchange,提问作者Jordi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:45:55