一、WCF bindings設定的影響
二、SSL資料傳輸在Java環境中的設定
三、JDK版本的影響
四、Java FQDN造成的問題
五、NetBeans使用Web Service的方法和修改部份程式碼
一、WCF Binding設定
WCF服務繫結(binding)
注意:SecurityMode 設定為"TransportWithMessageCredential"時,會忽略transport項目的ClientCredentialType。
有兩種解決方法:
(一)、在程式中修正java keystore 使用SSL安全協定傳輸資料,在使用web service前,必需設定接受憑證政策。
Step1.匯入憑證(向senslink網站索取),利用java的keytool匯入(在jdk\bin\目錄下可找到),
輸入:keytool –keystore 匯入後的keystore存放位置 –alias 憑證匿名 –import –file 憑證位置 設定keystore密碼(後面會用到,要記住)
Step2.匯入成功後,可查詢已匯入的憑證(keytool –list –keystore keystore存放位置)
Step.3 設定授權政策
將以下程式片段加入main class
(二)、修正整個windows系統的keystore
開發時,需將信任憑證加入Java_Home\JDK1.xx.x\jre\bin環境中,因此以下指令皆需在此路徑下執行
Step1. 列出目前keystore裡的信任憑證
指令:keytool –list –keystore ..\lib\security\cacerts
系統預設密碼:changeit
Step2.加入信任憑證
●在瀏覽器中,將要加入信任的憑證匯出,然後匯入java keystore IE => 網際網路選項 => 內容 => 憑證,選擇憑證後,匯出DER編碼二位元X.509(.CER)
●將憑證匯入Java keystore
Ex: 匯入senslink憑證
指令:keytool –import –alias senslink –keystore ..\lib\security\cacerts -file d:\senslink\senslink.cer
系統預設密碼:changeit
●查詢是否匯入成功:
指令:keytool –list –alias senslink –keystore ..\lib\security\cacerts
系統預設密碼:changeit
三、在NetBeans建立新的專案
設定完上述的步驟後,在NetBeans建立新的Java Project
在Java環境下要可以使用parsing web service WSDL的定義語言,並產生相關的class,有不同的Library可以使用。
ex: Metro 2.0、Apache Axis 2.0...等符合WS-Security標準的Library
本範例使用的是Metro 2.0
1.建立專案,並在Library加入Metro 2.0後,產生web service client
此時,可能會有一些錯誤
➀SSL交換訊息錯誤:
SSLException: HelloRequest followed by an unexpected handshake message
這個問題是在SSL連線時,無法解析Server端的訊息所產生的。
它是一個Java的安全性問題,可在這裡找到相關的訊息。
解決的方法:
將JDK更新到1.6.0 update 23以後的版本
②web service定義重複:
[ERROR] duplicate "message" entity: "IWcfRequestProcessor_ProcessRequests_InputMessage line 1 of https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl
解決的方法:
這個問題有可能是FQDN造成的錯誤,在網址使用domain的情況下,在Intranet內的電腦,有可能會有許多符合條件的路徑指向Service.svc,有可能是127.0.0.1找到一次,localhost又找到一次,所以會造成重複,但如果由Intranet外部使用網域名稱就可以解決這個問題
2.順利由WSDL產生服務相關的檔案後,
可利用NetBeans的Insert Code產生呼叫web service的程式片段,
在main class上點選右鍵,選擇Insert Code => Call web service operation =>選擇要使用的web service 方法
3.加入使用者認證的程式
利用WSBindingProvider.USERNAME_PROPERTY和WSBindingProvider.PASSWORD_PROPERTY加入認證的使用者名稱和密碼
③執行程式呼叫web service後,可能會發生以下的錯誤:
javax.xml.ws.WebServiceException:
Cannot find 'https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl' wsdl. Place the resource correctly in the classpath.
解決方法:
修正service constructor程式片段
原本的程式:
References:
1.WCF服務繫結詳細資料
2.Java jdk bug造成的SSL錯誤
3.Java FQDN造成的message entity duplicated錯誤
4.加入service後,卻在執行時找不到service路徑
WCF服務繫結(binding)
- BasicHttpBinding:一種 HTTP 通訊協定繫結,可用於連線至 Web 服務,並符合 WS-I Basic Profile 規格 (例如,以 ASP.NET Web 服務為基礎的服務)。
- WSHttpBinding:一種互通的繫結,可用於連線至符合 WS-* 通訊協定的端點。
- NetNamedPipeBinding:使用 .NET Framework 以連線至同一部電腦上的其他 WCF 端點。
- NetMsmqBinding:使用 .NET Framework 以建立與其他 WCF 端點的佇列訊息連線。
注意:SecurityMode 設定為"TransportWithMessageCredential"時,會忽略transport項目的ClientCredentialType。
<security mode="TransportWithMessageCredential">
< transport clientCredentialType="None" />
< message clientCredentialType="UserName" />
</security>
二、解決windows環境下java的ssl資料存取問題有兩種解決方法:
(一)、在程式中修正java keystore 使用SSL安全協定傳輸資料,在使用web service前,必需設定接受憑證政策。
Step1.匯入憑證(向senslink網站索取),利用java的keytool匯入(在jdk\bin\目錄下可找到),
輸入:keytool –keystore 匯入後的keystore存放位置 –alias 憑證匿名 –import –file 憑證位置 設定keystore密碼(後面會用到,要記住)
Step2.匯入成功後,可查詢已匯入的憑證(keytool –list –keystore keystore存放位置)
Step.3 設定授權政策
將以下程式片段加入main class
//.keystore位置
System.setProperty("javax.net.ssl.trustStore", "d:\\senslinkcert\\client.keystore");
System.setProperty("javax.net.ssl.keyStore", "d:\\senslinkcert\\client.keystore");
//.keystore密碼
System.setProperty("javax.net.ssl.trustStorePassword", "keystorePassword");
System.setProperty("javax.net.ssl.keyStorePassword", " keystorePassword ");
(二)、修正整個windows系統的keystore
開發時,需將信任憑證加入Java_Home\JDK1.xx.x\jre\bin環境中,因此以下指令皆需在此路徑下執行
Step1. 列出目前keystore裡的信任憑證
指令:keytool –list –keystore ..\lib\security\cacerts
系統預設密碼:changeit
Step2.加入信任憑證
●在瀏覽器中,將要加入信任的憑證匯出,然後匯入java keystore IE => 網際網路選項 => 內容 => 憑證,選擇憑證後,匯出DER編碼二位元X.509(.CER)
●將憑證匯入Java keystore
Ex: 匯入senslink憑證
指令:keytool –import –alias senslink –keystore ..\lib\security\cacerts -file d:\senslink\senslink.cer
系統預設密碼:changeit
●查詢是否匯入成功:
指令:keytool –list –alias senslink –keystore ..\lib\security\cacerts
系統預設密碼:changeit
三、在NetBeans建立新的專案
設定完上述的步驟後,在NetBeans建立新的Java Project
在Java環境下要可以使用parsing web service WSDL的定義語言,並產生相關的class,有不同的Library可以使用。
ex: Metro 2.0、Apache Axis 2.0...等符合WS-Security標準的Library
本範例使用的是Metro 2.0
1.建立專案,並在Library加入Metro 2.0後,產生web service client
此時,可能會有一些錯誤
➀SSL交換訊息錯誤:
SSLException: HelloRequest followed by an unexpected handshake message
這個問題是在SSL連線時,無法解析Server端的訊息所產生的。
它是一個Java的安全性問題,可在這裡找到相關的訊息。
解決的方法:
將JDK更新到1.6.0 update 23以後的版本
②web service定義重複:
[ERROR] duplicate "message" entity: "IWcfRequestProcessor_ProcessRequests_InputMessage line 1 of https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl
解決的方法:
這個問題有可能是FQDN造成的錯誤,在網址使用domain的情況下,在Intranet內的電腦,有可能會有許多符合條件的路徑指向Service.svc,有可能是127.0.0.1找到一次,localhost又找到一次,所以會造成重複,但如果由Intranet外部使用網域名稱就可以解決這個問題
2.順利由WSDL產生服務相關的檔案後,
可利用NetBeans的Insert Code產生呼叫web service的程式片段,
在main class上點選右鍵,選擇Insert Code => Call web service operation =>選擇要使用的web service 方法
3.加入使用者認證的程式
利用WSBindingProvider.USERNAME_PROPERTY和WSBindingProvider.PASSWORD_PROPERTY加入認證的使用者名稱和密碼
import com.sun.xml.ws.developer.WSBindingProvider;
③執行程式呼叫web service後,可能會發生以下的錯誤:
javax.xml.ws.WebServiceException:
Cannot find 'https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl' wsdl. Place the resource correctly in the classpath.
解決方法:
修正service constructor程式片段
原本的程式:
static {
SERVICE_WSDL_LOCATION = namespace.Service.class.getResource("https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl");
WebServiceException e = null;
if (SENSLINKSERVICE_WSDL_LOCATION == null) {
e = new WebServiceException("Cannot find 'https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl' wsdl. Place the resource correctly in the classpath.");
}
SERVICE_EXCEPTION = e;
}
修正後:
static {
URL url = null;
WebServiceException e = null;
try {
URL baseUrl;
baseUrl = namespace.Service.class.getResource(".");
url = new URL(baseUrl, "https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl");
} catch (java.net.MalformedURLException ex) {
e = new WebServiceException("Cannot find 'https://xxxxxxxxxxxxxxxxxxxxxx/Service.svc?wsdl' wsdl. Place the resource correctly in the classpath.");
}
SERVICE_WSDL_LOCATION = url;
SERVICE_EXCEPTION = e;
}
這樣一來,就可以正常的從Java client呼叫.net WCF Web Service
References:
1.WCF服務繫結詳細資料
2.Java jdk bug造成的SSL錯誤
3.Java FQDN造成的message entity duplicated錯誤
4.加入service後,卻在執行時找不到service路徑
2 則留言:
kaochiuan,能否請教一些問題。
依著您所提供的資料﹐我試著練習﹐可是在最後執行卻出現了如下的錯誤
java.lang.ClassCastException: $Proxy41 cannot be cast to com.sun.xml.internal.ws.developer.WSBindingProvider
at web3.javaClient.main(javaClient.java:33)
第33行是 WSBindingProvider bp = (WSBindingProvider) port;
public static void main(String[] args) {
//.keystore位置
System.setProperty("javax.net.ssl.trustStore", "C:\\Java\\Certificate\\myTrustStore");
System.setProperty("javax.net.ssl.keyStore", "C:\\Java\\Certificate\\myTrustStore");
//.keystore密碼
System.setProperty("javax.net.ssl.trustStorePassword", "q2000s");
System.setProperty("javax.net.ssl.keyStorePassword", " q2000s");
org.tempuri.ProductsService service=null;
org.tempuri.IProductsService port=null;
try{
service = new org.tempuri.ProductsService();
port = service.getBasicHttpBindingIProductsService();
WSBindingProvider bp = (WSBindingProvider) port;
bp.getRequestContext().put(WSBindingProvider.USERNAME_PROPERTY, "testman");
bp.getRequestContext().put(WSBindingProvider.PASSWORD_PROPERTY, "testman123");
System.out.println(port.saySomething("Hello"));
}catch(Exception er){
er.printStackTrace();
}
}
請問這個錯誤知道是什麼原因嗎?煩請不吝指教﹐謝謝。
不好意思,過這麼久才看見您的留言
我發現您的程式有一部份有問題
在這行程式中,
port = service.getBasicHttpBindingIProductsService();
port其實應該是要取得serviceEndPoint,不是直接使用Service,所以造成java在cast轉型時,發現型別不對丟出例外。
張貼留言