Apereo CAS OpenID Connect 动态客户端注册(Dynamic Client Registration)端到端实战指南

发布时间:2026/9/24 19:11:13
Apereo CAS OpenID Connect 动态客户端注册(Dynamic Client Registration)端到端实战指南 后端认证鉴权单点登录【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载导读本文围绕 Apereo CAS 的 OpenID ConnectOIDC动态客户端注册能力展开覆盖PROTECTED与OPEN两种注册模式、初始访问令牌获取、客户端注册提交、以及注册后客户端的读取与更新含客户端密钥过期轮换三个核心端点的完整调用链路。读完本文你将掌握如何配置 CAS 动态注册相关属性、如何通过curl完成一次受保护的客户端注册并能理解注册请求字段到OidcRegisteredService服务定义之间的映射与校验逻辑附仓库源码与测试用例佐证。一、动态客户端注册规范背景与 CAS 实现概览OpenID Connect 规范体系中的Dynamic Client Registration 1.0允许客户端应用在运行时向授权服务器OpenID Provider提交自身的注册信息由服务器为其颁发client_id与client_secret从而免去运维人员手工在服务注册表中录入每一个应用的步骤。CAS 以原生支持的方式实现了该规范动态注册产生的客户端会作为标准的OidcRegisteredService服务定义写入 CAS 的服务注册表与静态配置的服务享受完全一致的后续处理能力。从源码常量看OidcConstants.java动态客户端注册功能由三个端点协同完成端点路径相对/cas常量定义HTTP 方法用途/oidc/registerREGISTRATION_URL registerPOST提交应用注册记录完成动态客户端注册/oidc/initTokenREGISTRATION_INITIAL_TOKEN_URL initTokenGET在PROTECTED模式下用 Basic 认证换取注册所需的 master access token/oidc/clientConfigCLIENT_CONFIGURATION_URL clientConfigGET/PATCH读取或更新已动态注册的客户端实体注册端点接收POST请求请求体Body即应用注册记录application registration record。默认情况下 CAS 运行在PROTECTED模式注册端点要求调用方先通过用户认证。三个端点的控制器实现分别位于OidcDynamicClientRegistrationEndpointController.javaOidcInitialAccessTokenController.javaOidcClientConfigurationEndpointController.java一次成功的注册操作其响应中会包含所注册实体的信息并附带位于registration_access_token字段的访问令牌该令牌可被用于更新或检索位于registration_client_uri字段的注册实体。二、注册模式PROTECTED 与 OPEN动态注册的运行模式由配置项cas.authn.oidc.registration.dynamic-client-registration-mode控制对应源码中的枚举DynamicClientRegistrationModes见 OidcClientRegistrationProperties.java支持两种取值PROTECTED默认注册对所有人封闭保护调用方必须先获取并出示 master access token 才能注册客户端。OPEN注册向所有人开放任何人都可以直接提交注册请求。两种模式在行为上的关键差异可以从注册请求翻译器的校验逻辑中得到印证OidcDefaultClientRegistrationRequestTranslator.java当模式不是PROTECTED即OPEN时如果注册请求携带了logo_uri或policy_uriCAS 会强制校验这两个 URI 的主机名必须与redirect_uris数组中某个 URI 的主机名一致否则直接抛出IllegalArgumentExceptionInvalid logo uri from an unknown host/Invalid policy uri from an unknown host拒绝注册。这是 CAS 在开放模式下防止滥用如借道 CAS 投放第三方广告图或恶意政策链接的一道内置防线。结论即使你选择开放注册logo_uri与policy_uri的主机绑定校验依然生效而PROTECTED模式下则无此限制因为调用方已经过令牌认证。此外配置模型中还提供cas.authn.oidc.registration.dynamic-client-registration-enabled默认true作为总开关。测试用例 OidcDynamicClientRegistrationEndpointControllerTests.java 验证了当该属性设为false时访问注册端点将返回501 Not Implemented。三、PROTECTED 模式实战从 /oidc/initToken 获取 master 令牌在PROTECTED模式下注册客户端之前必须先获得一个包含必要 scope 的master access token即初始访问令牌。CAS 通过/oidc/initToken端点颁发该令牌该端点接受GET请求受Basic 认证方案保护认证凭据来自 CAS 配置中为动态注册指定的initial-access-token-user与initial-access-token-password响应中的access_token即为 master token后续所有动态注册请求都必须将其作为Bearer授权头传递。3.1 配置初始访问令牌凭据cas: authn: oidc: registration: dynamic-client-registration-mode: PROTECTED initial-access-token-user: casuser initial-access-token-password: Mellon这两个属性的默认值在配置模型中为空null。从 OidcInitialAccessTokenController.java 的构造函数可以看到如果二者未配置CAS 会使用RandomUtils.randomAlphabetic(8)生成随机用户名与密码这意味着你无法预知凭据因此生产环境必须显式配置。该控制器在PROTECTED模式下通过BasicAuthExtractor提取请求中的 Basic 凭据并使用InMemoryProfileService配合NoOpPasswordEncoder完成比对即明文比对配置值。3.2 调用 initToken 获取令牌curl -u casuser:Mellon https://sso.example.org/cas/oidc/initToken以casuser:Mellon为例其响应大致为{ access_token: master-access-token, token_type: bearer, expires_in: 28800, scope: openid client_registration_scope }从源码看OidcInitialAccessTokenController.javaCAS 为该令牌声明的 scope 为openid与client_registration_scopeOidcConstants.CLIENT_REGISTRATION_SCOPE其中client_registration_scope正是后续访问/oidc/register所需的关键 scope。3.3 边界行为测试用例佐证OidcInitialAccessTokenControllerTests.java 对initToken端点做了全面验证OPEN 模式下访问返回406 Not AcceptableverifyNotAllowed因为开放模式无需 master tokenPROTECTED 模式下凭据正确返回200 OK且响应中存在access_token字段verifyPasses凭据错误返回401 UnauthorizedverifyAuthFails缺少 Authorization 头返回401 UnauthorizedverifyAuthMissing请求的 Issuer 与配置不一致返回400 Bad RequestverifyMismatchedEndpoint即所有 OIDC 端点都会先经过IssuerService.validateIssuer的发行方校验。四、提交注册请求/oidc/register获取 master token 后即可向注册端点发起POST请求curl -X POST https://sso.example.org/cas/oidc/register \ -H Authorization: Bearer master-access-token \ -H Content-Type: application/json \ -d { application_type: web, redirect_uris: [https://client.example.org/callback5, https://client.example.org/callback11], client_name: My Example Client, logo_uri: https://client.example.org/logo.png, policy_uri: https://client.example.org/policy, tos_uri: https://client.example.org/tos, subject_type: pairwise, token_endpoint_auth_method: client_secret_basic, grant_types: [authorization_code], response_types: [code], id_token_signed_response_alg: RS256, id_token_encrypted_response_alg: RSA1_5, id_token_encrypted_response_enc: A128CBC-HS256, userinfo_encrypted_response_alg: RSA1_5, contacts: [ve7jtbexample.org, maryexample.org] }4.1 注册请求支持的字段注册请求体的字段由 OidcClientRegistrationRequest.java 定义以下为核心字段JSON 属性名与 OIDC 规范保持一致请求字段JSON说明默认值/备注redirect_uris允许的回调地址列表必填翻译后以\|拼接为服务的serviceId空列表包含#片段的 URI 会被拒绝application_type应用类型web/nativewebclient_name客户端展示名称未提供时 CAS 生成 8 位随机字母名称随机生成subject_typepublic或pairwisepairwise时自动装配PairwiseOidcRegisteredServiceUsernameAttributeProvider—logo_uri客户端 Logo 地址映射为服务定义的 Logo见 OPEN 模式主机校验policy_uri客户端政策页地址映射为informationUrl见 OPEN 模式主机校验tos_uri服务条款地址映射为privacyUrl—token_endpoint_auth_method令牌端点认证方式client_secret_basicgrant_types支持的授权类型列表未提供时默认authorization_coderesponse_types支持的响应类型列表未提供时默认codejwks_uri/jwks客户端公钥来源URI 或内嵌 JWKS内嵌 JWKS 中缺少kid的密钥会被自动补上 6 位随机kid—sector_identifier_urisector 标识符 URI用于 pairwise 计算提供时 CAS 会 GET 该地址并校验返回的 URI 列表与redirect_uris完全一致contacts联系人列表包含的条目按邮箱解析为emailname否则作为姓名—default_acr_values默认 ACR 值列表映射为注册服务的多因素认证策略MFA provider 集合—id_token_signed_response_alg/id_token_encrypted_response_alg/id_token_encrypted_response_encID Token 签名/加密算法配置后自动开启 ID Token 签名/加密—userinfo_signed_response_alg/userinfo_encrypted_response_alg/userinfo_encrypted_response_encUserInfo 响应签名/加密算法加密编码默认A128CBC-HS256introspection_signed_response_alg等introspection 响应的签名/加密算法—post_logout_redirect_uris注销后允许跳转的地址映射为服务logoutUrl逗号分隔—tls_client_auth_subject_dn/tls_client_auth_san_dns等TLS 客户端认证mTLS相关 SAN/Subject DN 字段—backchannel_token_delivery_mode/backchannel_client_notification_endpoint/backchannel_authentication_request_signing_alg/backchannel_user_code_parameterCIBAClient-Initiated Backchannel Authentication相关字段见 4.3 校验规则request_object_signing_alg请求对象签名算法—4.2 成功响应的结构与字段注册成功后端点返回201 Created源码见 OidcDynamicClientRegistrationEndpointController.java响应体由 OidcClientRegistrationUtils.java 组装包含{ client_id: generated-client-id, client_secret: generated-client-secret, client_secret_expires_at: 0, client_id_issued_at: 1690000000, registration_access_token: registration-scope-access-token, registration_client_uri: https://sso.example.org/cas/oidc/clientConfig?client_idgenerated-client-id, redirect_uris: [https://client.example.org/callback5, https://client.example.org/callback11], grant_types: [authorization_code, implicit, ...], response_types: [code, token, ...], token_endpoint_auth_method: client_secret_basic, jwks_uri: ..., logo: ..., policy_uri: ..., tos_uri: ..., contacts: [ve7jtbexample.org, maryexample.org] }关键字段说明client_id/client_secretCAS 通过clientIdGenerator/clientSecretGenerator生成client_secret在写入服务注册表前会经registeredServiceCipherExecutor加密存储响应中返回的是解密后的明文仅此一次暴露。registration_access_token注册级访问令牌。从源码看它的 scope 为client_configuration_scopeOidcConstants.CLIENT_CONFIGURATION_SCOPE签发对象service即该客户端专属的clientConfigURI因此它只能用于操作当前这个注册实体不能用于其他客户端OidcDynamicClientRegistrationEndpointController.java。registration_client_uri指向该客户端的配置管理端点/oidc/clientConfig?client_id...配合registration_access_token即可读取/更新本客户端。client_secret_expires_at仅在客户端密钥设置了过期时间时出现UTC 秒级时间戳未设置时为0/不返回。client_id_issued_at动态注册时间UTC 秒级时间戳来源于注册时写入服务属性的OIDC_DYNAMIC_CLIENT_REGISTRATION_DATE。4.3 内置校验规则翻译器源码视角注册请求在落库前会经过 OidcDefaultClientRegistrationRequestTranslator.java 的翻译与校验主要规则包括Redirect URI 禁止携带 fragment任一redirect_uris中包含#即拒绝对应测试verifyBadRedirect返回400。Sector Identifier URI 一致性校验若提供sector_identifier_uriCAS 会以GET请求拉取其内容JSON 数组并强制要求该数组与请求中的redirect_uris完全一致否则抛出Invalid sector identifier uri。OPEN 模式下的 Logo/Policy URI 主机校验见本文第二节。CIBA backchannel 端点校验当backchannel_token_delivery_mode为push或ping时必须提供backchannel_client_notification_endpoint且该端点必须是https://开头对应测试verifyMissingBackchannelEndpoint。默认授权/响应类型未显式声明grant_types/response_types时分别回退为authorization_code/codescope 默认采用 discovery 配置中的cas.authn.oidc.discovery.scopes列表。4.4 失败场景一览测试用例佐证OidcDynamicClientRegistrationEndpointControllerTests.java 覆盖了以下行为场景预期 HTTP 状态未携带 Bearer 令牌直接 POST401 Unauthorized携带令牌但请求体为非法 JSON400 Bad Requestredirect_uris含 fragment400 Bad Request合法的完整注册请求含 MFA ACR、pairwise、加密算法、联系人201 Created功能开关dynamic-client-registration-enabledfalse501 Not ImplementedJWKS 中kid引用系统属性防注入校验400 Bad Request且响应无jwks五、注册后的管理/oidc/clientConfig 读取与更新应用定义被动态注册到 CAS 后可以通过/oidc/clientConfig端点进行读取或更新OidcClientConfigurationEndpointController.java支持GET读取与PATCH更新两种操作每次操作都需要携带clientId参数CAS 依据它定位先前注册的实体PATCH更新请求还可以在请求体中携带更新后的注册记录更新过程中 CAS 会检查客户端密钥是否过期若过期则自动生成新密钥。5.1 读取客户端配置curl https://sso.example.org/cas/oidc/clientConfig?client_idclient-id \ -H Authorization: Bearer registration-access-token返回200 OK响应体结构与注册响应一致client_id、client_secret、redirect_uris等。若clientId不存在返回400 Bad RequestUnknown client。5.2 更新客户端配置含密钥轮换curl -X PATCH https://sso.example.org/cas/oidc/clientConfig?client_idclient-id \ -H Authorization: Bearer registration-access-token \ -H Content-Type: application/json \ -d { redirect_uris: [https://client.example.org/new-callback], client_name: My Example Client (Renamed) }PATCH语义源码 OidcClientConfigurationEndpointController.java如下请求体可选为空时仅执行密钥过期检查不修改服务定义请求体非空时先通过翻译器将更新记录应用到现有OidcRegisteredServicetranslate(registrationRequest, Optional.of(service))再保存只要请求体非空或发生了密钥更新就调用ServicesManager.save(service)持久化。5.3 客户端密钥过期与自动轮换动态注册的客户端密钥可以设置有效期对应配置项cas.authn.oidc.registration.client-secret-expiration默认0表示永不过期cas: authn: oidc: registration: client-secret-expiration: P14D该属性为DurationCapable见 OidcClientRegistrationProperties.java示例值P14D表示注册日期后 14 天按 UTC 计算密钥过期注册时OidcDefaultClientRegistrationRequestTranslator.java若配置了过期时间新签发的密钥会带上到期时间戳读取或更新时processClientSecretExpirationIfAnyCAS 会用clientSecretValidator.isClientSecretExpired逐一对密钥判活已过期的密钥由clientSecretGenerator生成新值替换并重新计算过期时间若动态注册服务名下已无任何密钥也会补发一个新密钥测试DefaultTests正是以client-secret-expirationP14D组合PROTECTED模式运行OidcDynamicClientRegistrationEndpointControllerTests.java。六、配置属性速查表动态注册相关的全部配置项位于cas.authn.oidc.registration命名空间下对应的配置模型类是 OidcClientRegistrationProperties.java配置属性类型默认值说明cas.authn.oidc.registration.dynamic-client-registration-mode枚举PROTECTED注册模式PROTECTED需 master token或OPEN开放注册cas.authn.oidc.registration.dynamic-client-registration-enabledbooleantrue动态注册功能总开关关闭后相关端点返回501cas.authn.oidc.registration.initial-access-token-userString空initToken的 Basic 认证用户名未配置则随机生成生产必须显式配置cas.authn.oidc.registration.initial-access-token-passwordString空initToken的 Basic 认证密码未配置则随机生成cas.authn.oidc.registration.client-secret-expirationDuration0动态签发客户端密钥的有效期如P14D0表示永不过期配置方式与其他 CAS 属性一致可通过application.yml/application.properties或 CAS 配置中心Spring Cloud Config、Vault 等下发。七、安全与运维建议生产环境务必显式配置initial-access-token-user/initial-access-token-password从源码看未配置时 CAS 会生成随机凭据届时无法预知也无法获取 master token导致动态注册不可用同时该凭据等效于注册任意客户端的钥匙应纳入密钥管理定期轮换。默认保持PROTECTED模式仅在可信内网或对客户端完全开放的业务场景下才考虑OPEN并注意 OPEN 模式仍受logo_uri/policy_uri与redirect_uris主机绑定的约束。利用client-secret-expiration建立密钥生命周期为动态注册的客户端设定短期密钥如P14D配合/oidc/clientConfig的自动轮换机制降低密钥泄露的长期风险密钥过期后客户端需主动调用clientConfig端点获取新密钥。结合服务注册表审计动态注册的客户端以OidcRegisteredService形式落入服务注册表markAsDynamicallyRegistered会写入动态注册标记与注册时间属性可通过服务管理界面或注册表查询梳理动态客户端清单registration_access_token仅具备client_configuration_scope作用域被限定在对应客户端的clientConfigURI 上不应外泄。注意 Issuer 校验三个端点都会校验请求的 Issuer 与cas.authn.oidc.issuer配置一致反代或负载均衡层务必保证 Host/Issuer 传递正确否则会得到400 Invalid issuer。总结Apereo CAS 的 OIDC 动态客户端注册提供了一条完整的运行时自助接入链路PROTECTED模式下先通过 Basic 认证从/oidc/initToken换取 master token再携带该令牌向/oidc/register提交符合 OIDC Dynamic Client Registration 规范的注册记录CAS 完成翻译、校验、落库后返回client_id、client_secret及专属的registration_access_token/registration_client_uri最后可通过/oidc/clientConfig对注册实体进行读取、更新与密钥轮换。整条链路在仓库源码与测试用例中均有完整实现与行为验证可在 OidcDynamicClientRegistrationEndpointController.java、OidcInitialAccessTokenController.java 及其对应测试中继续深入研读。赞分享后端认证鉴权单点登录【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载相关推荐Java Apereo CAS 客户端使用指南Java Apereo CAS 客户端使用指南 本指南基于 Apereo Java CAS Client https://github.com/apereo/jPoissonRecon在计算机视觉中的应用10个真实场景案例解析PoissonRecon在计算机视觉中的应用10个真实场景案例解析 泊松表面重建Poisson Surface Reconstruction 是计算机视觉Java Apereo CAS 客户端安装与使用指南Java Apereo CAS 客户端安装与使用指南 1. 项目目录结构及介绍 本节将概述 Java Apereo CAS Client 的仓库结构及其主要组成上一篇Paseo SDK Provider 指南模型选择、Provider 发现与 Agent 会话配置下一篇Python量化投资终极指南用mootdx轻松获取A股市场数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考