无法通过容器内的HandlerResolver动态设置基本身份验证标头

时间:2018-10-16 03:19:59

标签: spring cxf interceptor

我们需要将“基本身份验证授权”标头设置为所有出站SOAP调用。我们的J2EE应用程序使用spring作为SOAP客户端。

<bean id="myServices"
    class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
    <property name="serviceInterface"
        value="training.service.mybusinessservices.myBusinessServicesPort" />
    <property name="wsdlDocumentUrl" value="${my.service.wsdlDocumentUrl}" />
    <property name="endpointAddress" value="${my.service.endpoint}" />
    <property name="namespaceUri"
        value="http://training.org/myBusinessServices" />
    <property name="serviceName" value="myBusinessServices" />
    <property name="portName" value="myBusinessServices" />
    <property name="lookupServiceOnStartup" value="false" />
    <property name="handlerResolver" ref="serviceSecurityHandler" />
</bean>

我们的要求是根据调用的serviceName从中央存储获取用户名和密码。因此,方法是使用handlerResolver通过拦截器设置http标头(与使用JaxWsProxy ....用户名和密码属性相比)

我们的handlerResolver拦截器实现

@Override
public boolean handleMessage(SOAPMessageContext context) {
    logger.debug("handleMessage()-start");
    boolean isOutBound = true;

    try {

        Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        if(context.getMessage() !=null && outboundProperty.booleanValue()) {

            MessageLogger.logMessage(AuthConstants.HANDLE_MESSAGE, "Context not null " + context.getMessage(),AuthConstants.DEBUG, null);

            String sourceAppID = getValueByTagName(context,AuthConstants.SOURCE_APPID);
            String channelID = getValueByTagName(context,AuthConstants.CHANNEL_ID);




            logger.debug("Retrieving the basic auth token details for sourceAppID:{}, channelID:{}",sourceAppID,channelID );

            /*
             * Retrieve the Basic Auth Token for the key
             * sourceAppID~channelID
             * e.g.
             * MOBILEAPP~ONLINE
             * or
             * MYWEBAPP~PORTAL
             */
            String encodedBasicAuthCredentials = getAuthorizationDetails (sourceAppID, channelID);
            String[] userDetailsPair = getUserDetailsPairFromBasicAuthCredentials(encodedBasicAuthCredentials);
            logger.debug("Obtained the userDetailsPair:{}",userDetailsPair);
            if(userDetailsPair !=null && userDetailsPair.length ==2) {
                logger.debug("Settings the context header:{}",userDetailsPair);
                logger.debug("Settings the context with username:{} and password:{}",userDetailsPair[0],userDetailsPair[1]);
                context.put("javax.xml.ws.security.auth.username", userDetailsPair[0]);
                context.put("javax.xml.ws.security.auth.password", userDetailsPair[1]);

                //Came across a forum where it was recommended to call saveChanges() for container starting from Tomcat v8.0
                context.getMessage().saveChanges();
            }
            else {
                logger.error("The authorization header is not set because of unavailability for sourceAppID:{}, channelID:{}",sourceAppID,channelID );
            }

        } else {

            isOutBound = false;
        }

    }catch (Exception e) {
        logger.error("Exception  in handleMessage:{}", e.getMessage());
        if(logger.isDebugEnabled()){
            logger.error("Exception  in handleMessage:" , e);
        }
    }

    logger.debug("handleMessage()-end");
    return isOutBound;
}

相同的代码可以通过Junit正常工作

但是当我通过JBOSS EAP 7.0进行测试时,观察到未设置Authorization标头。 还观察到在JBOSS内部,CXF优先作为客户端impl,并且未设置Authorization标头

任何指针都会很有帮助

1 个答案:

答案 0 :(得分:0)

使用org.apache.cxf.jaxws.JaxWsProxyFactoryBean解决了此问题,并使用outInterceptor替换了处理程序

所以现在的配置看起来像

<bean id="saajOutInterceptor" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean id="myServices" factory-bean="myServicesClientFactory"
        factory-method="create" />
<bean id="myServicesClientFactory"
    class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
    <property name="serviceInterface"
        value="training.service.mybusinessservices.myBusinessServicesPort" />
    <property name="wsdlLocation" value="${my.service.wsdlDocumentUrl}" />
    <property name="address" value="${my.service.endpoint}" />
        <property name="outInterceptors">
            <list>
                <ref bean="saajOutInterceptor" /> <!-- This important, if we need to read any data from the requestXml and generate dynamic auth headers -->
                <ref bean="clientAuthInterceptor" />
            </list>
        </property>
</bean>

参考文章

  

How to dynamically add HTTP headers in CXF client?

     

注意确保已包含cxf-rt-bindings-soap-3.x.x.jar(   SAAJOutInterceptor拦截器)

因此,通过以下方法,现在基本身份验证标头是动态生成的并且可以正常工作