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

如何将xsd/xsi命名空间声明从子元素移至saml:Assertion元素?

问题

我开发了一个Java + Spring Boot应用,使用jaxws-maven-plugin基于.wsdl和.xsd文件生成源码。发送SOAP请求后,返回的响应与客户端提供的预期示例存在差异。

预期响应

<soapenv:Envelope>
   <soapenv:Body>
      <wst13:SecResponse>
         <wst13:SecToken>
            <saml:Assertion ID="A-123"
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
               <saml:AttributeStatement>
                  <saml:Attribute Name="ClientID">
                     <saml:AttributeValue xsi:type="xsd:string">hello</saml:AttributeValue>
                  </saml:Attribute>
               </saml:AttributeStatement>
            </saml:Assertion>
         </wst13:RequestedSecurityToken>
      </wst13:RequestSecurityTokenResponse>
   </soapenv:Body>
</soapenv:Envelope>

实际响应

<soapenv:Envelope>
   <soapenv:Body>
      <wst13:SecResponse>
         <wst13:SecToken>
            <saml:Assertion ID="A-123"
                    xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
               <saml:AttributeStatement>
                  <saml:Attribute Name="ClientID">
                     <saml:AttributeValue
                             xsi:type="xsd:string"
                             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">hello</saml:AttributeValue>
                  </saml:Attribute>
               </saml:AttributeStatement>
            </saml:Assertion>
         </wst13:RequestedSecurityToken>
      </wst13:RequestSecurityTokenResponse>
   </soapenv:Body>
</soapenv:Envelope>

核心差异

预期中xsd和xsi命名空间定义在saml:Assertion元素上,但实际生成的响应里这两个命名空间被放在了saml:AttributeValue元素上。我需要将这两个命名空间声明从saml:AttributeValue移至saml:Assertion元素。

已尝试的方案

  • 自定义继承NamespacePrefixMapper的命名空间映射器,只能把xmlns:xsi移到根元素,不符合需求;
  • 尝试使用Marshaller监听器,但没找到正确的实现方式。

解决方案

方法1:修改生成的Assertion类(临时验证用)

找到jaxws-maven-plugin生成的Assertion类,在类上添加@XmlNs注解指定xsd和xsi的命名空间:

@XmlType(name = "Assertion", namespace = "urn:oasis:names:tc:SAML:2.0:assertion")
@XmlRootElement(namespace = "urn:oasis:names:tc:SAML:2.0:assertion")
@XmlNs(prefix = "xsd", namespaceURI = "http://www.w3.org/2001/XMLSchema")
@XmlNs(prefix = "xsi", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
public class Assertion {
    // 原有代码逻辑
}

⚠️注意:重新生成代码时这个修改会被覆盖,仅适合临时验证效果。

方法2:自定义Marshaller监听器强制添加命名空间

创建一个监听器,在Assertion对象序列化前,手动为对应的XML元素添加命名空间声明:

public class AssertionNamespaceListener extends Marshaller.Listener {
    @Override
    public void beforeMarshal(Object source) {
        if (source instanceof Assertion) {
            try {
                // 获取JAXB上下文并定位Assertion元素
                JAXBContext context = JAXBContext.newInstance(Assertion.class);
                JAXBIntrospector introspector = context.createJAXBIntrospector();
                QName elementName = introspector.getElementName(source);
                
                // 如果Marshaller输出到DOM节点,直接操作节点添加属性
                if (source instanceof Node) {
                    Node assertionNode = (Node) source;
                    if (assertionNode instanceof Element) {
                        Element assertionElement = (Element) assertionNode;
                        assertionElement.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
                        assertionElement.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
                    }
                }
            } catch (JAXBException e) {
                e.printStackTrace();
            }
        }
    }
}

然后在配置JAX-WS代理时注册这个监听器:

@Bean
public JaxWsPortProxyFactoryBean servicePort() {
    JaxWsPortProxyFactoryBean factory = new JaxWsPortProxyFactoryBean();
    // 配置WSDL地址、服务接口等参数...
    
    // 获取并配置Marshaller
    Marshaller marshaller = JAXBContext.newInstance(Assertion.class).createMarshaller();
    marshaller.setListener(new AssertionNamespaceListener());
    factory.setMarshaller(marshaller);
    
    return factory;
}

方法3:修改XSD文件(推荐持久化方案)

如果有权限修改对应的SAML XSD文件,在Assertion元素的定义中显式绑定xsd和xsi命名空间:

<xs:element name="Assertion" type="saml:AssertionType">
    <xs:annotation>
        <xs:appinfo>
            <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
                <jaxb:namespacePrefixes>
                    <jaxb:namespacePrefix prefix="xsd" uri="http://www.w3.org/2001/XMLSchema"/>
                    <jaxb:namespacePrefix prefix="xsi" uri="http://www.w3.org/2001/XMLSchema-instance"/>
                </jaxb:namespacePrefixes>
            </jaxb:bindings>
        </xs:appinfo>
    </xs:annotation>
</xs:element>

这样重新生成Java类时,Assertion类会自动包含这些命名空间配置,Marshaller序列化时会将命名空间声明放在saml:Assertion元素上。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:14:54