2012-08-16 52 views
7

我在使用Apache CXF爲Web服務請求設置HTTP授權頭時遇到了一些麻煩。我有我的客戶端安裝到春季:通過CXF攔截器不工作的HTTP基本身份驗證

<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" /> 
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> 

<bean id="myHTTPAuthInterceptor" class="my.app.MyHTTPAuthInterceptor" autowire="constructor" /> 

<bean id="webServiceFactory" class="my.app.WebServiceFactory"> 
    <property name="wsdlLocation" value="classpath:/my/app/webservice.wsdl" /> 
    <property name="serviceURL"> 
     <jee:jndi-lookup jndi-name="webservice/url" /> 
    </property> 
    <property name="inInterceptors"> 
     <list> 
      <ref bean="loggingInInterceptor" /> 
     </list> 
    </property> 
    <property name="outInterceptors"> 
     <list> 
      <ref bean="loggingOutInterceptor" /> 
      <ref bean="myHTTPAuthInterceptor" /> 
     </list> 
    </property> 
</bean> 

<bean id="myWebService" factory-bean="webServiceFactory" factory-method="getInstance" /> 

頁眉通過MyHTTPAuthInterceptor這樣設置:

public MyHTTPAuthInterceptor(ConfigDao configDao) 
{ 
    super(Phase.POST_PROTOCOL); 

    this.configDao = configDao; 
} 

@Override 
public void handleMessage(Message message) throws Fault 
{ 
    Map<String, List<?>> headers = (Map<String, List<?>>) message.get(Message.PROTOCOL_HEADERS); 

    String authString = configDao.getUsername() + ":" + config.getPassword(); 
    headers.put("Authorization", Collections.singletonList("Basic " + new String(Base64.encodeBase64(authString.getBytes())))); 
} 

使用用戶名和都設定爲「測試」,一切似乎都在日誌中確定:

Headers: {SOAPAction=[""], Accept=[*/*], Authorization=[Basic dGVzdDp0ZXN0]} 

但是,服務器返回HTTP 401:未經授權。

不知道發生了什麼問題,我通過更改我的Web服務客戶端工廠代碼採取了其他方法。我加了一個基本的授權策略,以客戶端的管道是這樣的:

HTTPConduit httpConduit = (HTTPConduit) client.getConduit(); 
AuthorizationPolicy authorizationPolicy = new AuthorizationPolicy(); 
authorizationPolicy.setUserName("test"); 
authorizationPolicy.setPassword("test"); 
authorizationPolicy.setAuthorizationType("Basic"); 
httpConduit.setAuthorization(authorizationPolicy); 

再次測試我的設置,相同的日誌(不同的順序雖然):

Headers: {SOAPAction=[""], Authorization=[Basic dGVzdDp0ZXN0], Accept=[*/*]} 

現在服務器的響應是200 OK!

問題解決了你可能會想到的問題,但第二種方法並不適合我。我的應用程序是一個多租戶環境,全部使用不同的用戶名和密碼。採用第二種方法,我無法重用我的客戶端。

如何讓我的攔截器正常工作?我是否陷入了錯誤的階段?頭文件的順序是否重要?如果是這樣,我該如何改變它?

回答

5

我的設置與您的設置幾乎完全相同,但是我將攔截器置於PRE_PROTOCOL階段。到目前爲止,我沒有遇到任何問題。你可以試試。

我覺得POST_PROTOCOL太晚了,因爲已經寫了太多的流。

+0

試了一下,但唉,沒有運氣...... – verhage 2012-11-09 10:34:05

+2

好吧,我得在這裏糾正自己。犯了一個錯誤。它確實有用!非常感謝,您的回答在此被接受:) – verhage 2012-11-09 10:37:45

3

如果您正在尋找外部化客戶端和認證最好的辦法是建立httpConduit在Spring上下文..通過在名稱屬性提SOAP地址

**in your spring context file...** 

<beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:jaxws="http://cxf.apache.org/jaxws" 
     ... 

    <bean id="properties" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer"> 
    <property name="locations"> 
     <util:list> 
      <value>file:${config.dir}/application.properties</value> 
     </util:list> 
    </property> 
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" /> 
</bean> 
    ... 
    <jaxws:client id="serviceClient" serviceClass="com.your.ServiceClass" address="${webservice.soap.address}" > 
    <jaxws:inInterceptors> 
     <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" > 
      <property name="prettyLogging" value="true" /> 
     </bean> 
    </jaxws:inInterceptors> 
    <jaxws:outInterceptors> 
     <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" > 
      <property name="prettyLogging" value="true" /> 
     </bean> 
    </jaxws:outInterceptors> 
    </jaxws:client> 
    ... 


applicaiton.properties 
--------------------- 
webservices.http.auth.username=userName 
webservices.http.auth.password=Password 
webservice.soap.address=https://your.service.url/services/service 

一)。這你可以在你的WSDL找到

Ex: if in your WSDL.. 
    <wsdl-definitions ... targetNamespace="http://your.target.namespace.com/" ...> 
    ... 
    <wsdl:port binding="tns:YourServiceSoapBinding" 
     name="YourServiceImplPort"> 
     <soap:address location="https://your.service.url/services/service" /> 

然後

... 
xmlns:http-conf="http://cxf.apache.org/transports/http/configuration" 
xmlns:sec="http://cxf.apache.org/configuration/security" 
... 
<http-conf:conduit name="https://your.service.url/services/service"> 
    <http-conf:authorization> 
     <sec:UserName>${webservices.http.auth.username}</sec:UserName> 
     <sec:Password>${webservices.http.auth.password}</sec:Password> 
     <sec:AuthorizationType>Basic</sec:AuthorizationType> 
    </http-conf:authorization> 
</http-conf:conduit> 

或者 B)name屬性應爲{}目標名稱portName.http_conduit

<http-conf:conduit name="{http://your.target.namespace.com/}YourServiceImplPort.http_conduit"> 
    <http-conf:authorization> 
     <sec:UserName>${webservices.http.auth.username}</sec:UserName> 
     <sec:Password>${webservices.http.auth.password}</sec:Password> 
     <sec:AuthorizationType>Basic</sec:AuthorizationType> 
    </http-conf:authorization> 
</http-conf:conduit>