发现文档
GET /.well-known/openid-configuration 返回 OpenID Connect 发现文档,客户端库靠它找到各端点和公钥。本页给出 v0.1.4 的实测输出,逐项说明字段从哪里来,并列出需要你主动处理的已知问题。
实测输出
以下是快速开始示例(只注册了一个 API scope orders.read、一个 RS256 签名密钥,其余全部默认)的真实响应,键按字母排序:
{
"authorization_endpoint": "http://localhost:5000/connect/authorize",
"authorization_response_iss_parameter_supported": true,
"backchannel_authentication_endpoint": "http://localhost:5000/connect/ciba",
"backchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_token_delivery_modes_supported": ["poll"],
"backchannel_user_code_parameter_supported": true,
"check_session_iframe": "http://localhost:5000/connect/checksession",
"claims._supported": [],
"code_challenge_methods_supported": ["plain", "S256"],
"device_authorization_endpoint": "http://localhost:5000/connect/deviceauthorization",
"end_session_endpoint": "http://localhost:5000/connect/endsession",
"frontchannel_logout_session_supported": true,
"frontchannel_logout_supported": true,
"grant_types_supported": [
"authorization_code", "client_credentials", "refresh_token", "implicit",
"urn:ietf:params:oauth:grant-type:device_code", "urn:openid:params:grant-type:ciba"
],
"id_token_signing_alg_values_supported": ["RS256"],
"introspection_endpoint": "http://localhost:5000/connect/introspect",
"issuer": "http://localhost:5000",
"jwks_uri": "http://localhost:5000/.well-known/openid-configuration/jwks",
"request_object_signing_alg_values_supported": [
"RS256", "RS384", "RS512", "PS256", "PS384", "PS512",
"ES256", "ES384", "ES512", "HS256", "HS384", "HS512"
],
"request_parameter_supported": true,
"response_modes_supported": ["form_post", "query", "fragment"],
"response_types_supported": [
"code", "token", "id_token", "id_token token",
"code id_token", "code token", "code id_token token"
],
"revocation_endpoint": "http://localhost:5000/connect/revocation",
"scopes_supported": ["orders.read", "offline_access"],
"subject_types_supported": ["public"],
"token_endpoint": "http://localhost:5000/connect/token",
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"],
"userinfo_endpoint": "http://localhost:5000/connect/userinfo"
}对应的 JWKS(/.well-known/openid-configuration/jwks)形如 {"keys":[{"alg":"RS256","e":"AQAB","kid":"...","kty":"RSA","n":"..."}]}。每把公钥都带 kid:验证密钥没有指定 kid 时,wicket 按 RFC 7638 指纹自动生成一个。
已知问题
1. 键名 claims._supported
标准字段名是 claims_supported,但 v0.1.4 输出的是 claims._supported(constants.go 中 DiscoveryClaimsSupported 常量的值多了一个点;同文件的 claims._parameter_supported、claims._locales_supported 常量也有同样问题,不过当前未被输出)。依赖 claims_supported 的客户端会认为服务端没有声明任何 claim。
在修复前,可以设置 opts.Discovery.ShowClaims = false 去掉这个错误的键。如果客户端确实需要 claims_supported,可以通过 CustomEntries 自行补上,但列表要手工维护,不会随资源配置自动更新。
2. 公布了未注册的端点
revocation_endpoint 与 device_authorization_endpoint 默认出现在文档中,但 v0.1.4 没有处理这两个路径(请求会落到宿主 handler,详见协议端点)。建议关闭:
opts.Endpoints.EnableTokenRevocationEndpoint = false
opts.Endpoints.EnableDeviceAuthorizationEndpoint = false // 同时移除 device_code 授权类型的公告3. 端点 URL 取自请求本身
除 issuer 外,所有 URL 都由当前请求拼出:协议看 r.TLS 是否为空,主机取 Host 头。v0.1.4 不读取 X-Forwarded-Proto / X-Forwarded-Host。在终止 TLS 的反向代理后面,文档里的端点会变成 http://...;请让代理透传原始 Host,并在上线前实际请求一次发现文档确认。issuer 只要设置了 opts.IssuerUri 就不受影响。
字段说明
| 字段 | 来源 / 控制开关 |
|---|---|
issuer | opts.IssuerUri(去掉末尾 /);未设置时取请求的 origin。生产环境务必显式设置 |
jwks_uri | Discovery.ShowKeySet 且至少有一把验证密钥时出现 |
*_endpoint、check_session_iframe | Discovery.ShowEndpoints 总开关 + Endpoints.Enable*Endpoint 逐项开关 |
mtls_endpoint_aliases | 仅 MutualTls.Enabled=true;v0.1.4 未实现 mTLS,不要开启 |
frontchannel_logout_*、backchannel_logout_* | Endpoints.EnableEndSessionEndpoint 为 true 时四项均为 true。注意 v0.1.4 的后端通道登出通知是空实现,并不会真正发送(见 ServerConfig) |
scopes_supported | ShowIdentityScopes:ShowInDiscoveryDocument=true 的身份资源;ShowApiScopes:同条件的 API scope,并固定追加 offline_access |
claims._supported | ShowClaims:上述可见资源的 UserClaims 去重合集(见已知问题 1) |
grant_types_supported | ShowGrantTypes。固定含 authorization_code、client_credentials、refresh_token、implicit;注入了自定义 ResourceOwnerPasswordValidator 才出现 password;设备授权与 CIBA 分别随对应端点开关出现 |
response_types_supported / response_modes_supported | ShowResponseTypes / ShowResponseModes,内容固定 |
token_endpoint_auth_methods_supported | ShowTokenEndpointAuthenticationMethods,取自已注册的 secret 解析器(basic、post) |
id_token_signing_alg_values_supported | 当前所有签名凭据的算法去重;无签名凭据时不出现 |
subject_types_supported | 固定 ["public"] |
code_challenge_methods_supported | 固定 ["plain","S256"];plain 实际还要求客户端 AllowPlainTextPkce=true |
request_parameter_supported、request_object_signing_alg_values_supported | 授权端点开启时固定输出 |
request_uri_parameter_supported | Endpoints.EnableJwtRequestUri=true(默认 false)时出现 |
authorization_response_iss_parameter_supported | 固定 true |
backchannel_token_delivery_modes_supported、backchannel_user_code_parameter_supported | CIBA 端点开启时,取自 opts.BackchannelAuthentication |
DiscoveryOptions
opts.Discovery(config/options/discovery_options.go)的全部字段:
| 字段 | 默认 | 作用 |
|---|---|---|
ShowEndpoints | true | 是否输出各端点 URL |
ShowKeySet | true | 是否输出 jwks_uri;为 false 时 JWKS 端点本身也返回 404 |
ShowIdentityScopes | true | scopes_supported 是否包含身份资源 |
ShowApiScopes | true | scopes_supported 是否包含 API scope(及 offline_access) |
ShowClaims | true | 是否输出 claim 列表 |
ShowResponseTypes | true | 是否输出 response_types_supported |
ShowResponseModes | true | 是否输出 response_modes_supported |
ShowGrantTypes | true | 是否输出 grant_types_supported |
ShowExtensionGrantTypes | true | 是否把扩展授权类型并入上一项 |
ShowTokenEndpointAuthenticationMethods | true | 是否输出客户端认证方式 |
CustomEntries | 空 map | 追加自定义键;与已有键重名时不覆盖,只记一条错误日志 |
ExpandRelativePathsInCustomEntries | true | CustomEntries 中以 ~/ 开头的字符串展开为绝对 URL |
ResponseCacheInterval | nil | 非 nil 且 ≥ 0 时输出 Cache-Control: max-age=<秒> 与 Vary: Origin;nil 时不设缓存头 |
关闭整个发现端点用的是 opts.Endpoints.EnableDiscoveryEndpoint = false(发现文档与 JWKS 都返回 404)。
示例
下面的配置已在快速开始示例上编译并实测:去掉了两个未注册端点和错误的 claims 键,加了缓存头与一个自定义条目。
opts := godi.GetRequired[*options.WicketOptions](root)
opts.IssuerUri = "https://id.example.com"
opts.Endpoints.EnableTokenRevocationEndpoint = false
opts.Endpoints.EnableDeviceAuthorizationEndpoint = false
opts.Discovery.ShowClaims = false
maxAge := 3600
opts.Discovery.ResponseCacheInterval = &maxAge
opts.Discovery.CustomEntries["service_documentation"] = "~/docs"实测结果:响应头出现 Cache-Control: max-age=3600 和 Vary: Origin;revocation_endpoint、device_authorization_endpoint、claims._supported 消失;grant_types_supported 不再含 device_code;新增 "service_documentation": "http://<当前主机>/docs"。