WildFly 35多模块EAR部署报错:SecurityDomain已关联ClassLoader
问题背景
我有一个包含至少2个WAR的EAR包:其中一个无需任何认证,另一个需通过Keycloak实现认证,认证配置仅通过针对该WAR的overlay文件实现。该配置在WildFly 26及之前版本可正常运行,升级至Jakarta EE体系的WildFly 35后,部署时触发报错。
报错日志
ttp-wf | "jboss.deployment.subunit."test-ear-2024.3.0-SNAPSHOT.ear"."test-web-2024.3.0-SNAPSHOT.war".undertow-deployment.UndertowDeploymentInfoService" => "Failed to start service
ttp-wf | Caused by: java.lang.IllegalStateException: ELY01148: A SecurityDomain has already been associated with the specified ClassLoader"
当前配置
Overlay的web.xml片段
<login-config> <auth-method>OIDC</auth-method> </login-config> ... <security-constraint> <display-name>security-domain</display-name> <web-resource-collection> <web-resource-name>security-domain</web-resource-name> <url-pattern>/html/internal/admin/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>role.admin</role-name> </auth-constraint> </security-constraint>
JBoss CLI配置命令
deployment-overlay add \ --name=configKeycloakAuth \ --content=/WEB-INF/web.xml=/entrypoint-wildfly-cli/config_oidc_web.xml \ --deployments=config-web-*.war \ --redeploy-affected set configVersion=2024.1.0 /subsystem=elytron-oidc-client/secure-deployment=config-web-$configVersion.war:add( \ provider-url=$ttpWebKeycloakBaseUrl/realms/$ttpWebKeycloakRealm, \ client-id=$ttpWebKeycloakClientId, \ ssl-required=$ttpWebKeycloakSslRequired, \ confidential-port=$ttpWebKeycloakConfidentialPort, \ use-resource-role-mappings=$ttpWebKeycloakUseResourceRoleMappings \ )
环境限制
- EAR必须保持
ear-subdeployments-isolated=false配置,子部署类加载器共享 - 无需认证的WAR的web.xml未声明security-domain,尝试设置
security-domain=none不被允许 - 当前使用WildFly 35,DEBUG日志无额外有效信息
解决方案
核心原因
WildFly 26之后的Jakarta EE版本中,当EAR子部署类加载器共享(ear-subdeployments-isolated=false)时,一旦某个WAR绑定了SecurityDomain,类加载器会被标记为已关联安全域,其他WAR无法再调整安全域配置,即使是设置为无安全域也会触发冲突。
调整方案
为需要认证的WAR单独指定安全域
在overlay的web.xml中显式指定安全域名称,避免使用默认安全域导致全局类加载器冲突:<login-config> <auth-method>OIDC</auth-method> <security-domain>keycloak-web-security</security-domain> </login-config>同时更新CLI命令,创建独立的安全域并关联到该WAR:
/subsystem=elytron/security-domain=keycloak-web-security:add( realms=[{realm-name=keycloak-oidc-realm}], default-realm=keycloak-oidc-realm, permission-mapper=default-permission-mapper ) /subsystem=elytron-oidc-client/realm=keycloak-oidc-realm:add( provider-url=$ttpWebKeycloakBaseUrl/realms/$ttpWebKeycloakRealm, client-id=$ttpWebKeycloakClientId, ssl-required=$ttpWebKeycloakSslRequired ) /subsystem=elytron-oidc-client/secure-deployment=config-web-$configVersion.war:add( security-domain=keycloak-web-security, use-resource-role-mappings=$ttpWebKeycloakUseResourceRoleMappings )为无需认证的WAR添加显式无安全域声明
通过jboss-web.xml为无认证WAR添加空的安全域标签,明确告知容器该WAR不使用安全域:<jboss-web> <security-domain/> </jboss-web>此配置可避免容器自动尝试关联默认安全域,减少类加载器冲突概率。
调整部署顺序(辅助措施)
先部署无需认证的WAR,再部署需要认证的WAR,降低类加载器初始化阶段的冲突概率,此方法仅作为辅助,核心解决依赖前两项配置。
验证要点
- 确保每个WAR的安全域配置完全独立,共享类加载器下无互相覆盖
- 检查WildFly Elytron子系统配置,确认无全局默认安全域自动绑定到所有Web部署
内容的提问来源于stack exchange,提问作者peatle_pp

