久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

AXIS完全總結(jié)

 Blex 2011-06-09

目錄

1.發(fā)布web服務(wù)

2.發(fā)布Web服務(wù)使用Handler來(lái)增強(qiáng)Web服務(wù)的功能

3.建立安全的AXIS服務(wù)(上)

4.建立安全的AXIS服務(wù)(下)

5.在AXIS服務(wù)間傳遞JavaBean及其安全解決

                          

AXIS學(xué)習(xí)筆記(一) 
ronghao100 原創(chuàng)

前天頭告訴我用SOAP WEB服務(wù)開(kāi)發(fā)一個(gè)客戶程序,用來(lái)與企業(yè)內(nèi)部的ERP進(jìn)行交互,。晚上趕快找相關(guān)的資料猛看,,總算對(duì)SOAP有了一定的認(rèn)識(shí),。干程序員這行真不容易,好象得不停地學(xué)習(xí)新東西,,一不小心就被淘汰:(不過(guò)學(xué)習(xí)也是個(gè)很有意思的事情,。好了,廢話少說(shuō),,讓我們開(kāi)始吧,。

一、軟件環(huán)境

1,、axis-1_2 (從apache網(wǎng)站下載最新axis-bin-1_2.zip解壓即可)

2,、Tomcat5.0 

3、JDK5.0

二,、相關(guān)配置

1,、在你的%TOMCAT_HOME%\common\lib下需要加入三個(gè)包 activation.jar、mail.jar,、tools.jar

2,、環(huán)境變量設(shè)置

  AXIS_HOME 即axis-bin-1_2.zip解壓的目錄(我的是在F:\soap\axis-1_2)

  AXIS_LIB   即 %AXIS_HOME%\lib

  AXISCLASSPATH 即 %AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery-0.2.jar;%AXIS_LIB%\commons-logging-1.0.4.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;也就是把%AXIS_LIB%下所用JAR文件都導(dǎo)入

三、實(shí)驗(yàn)一下

  在%AXIS_HOME%\webapps下找到axis文件夾,,將其整個(gè)拷貝到%TOMCAT_HOME%\webapps下,,啟動(dòng)

Tomcat,打開(kāi)瀏覽器訪問(wèn)http://localhost:8080/axis/,出現(xiàn)以下頁(yè)面說(shuō)明你配置成功了,。很簡(jiǎn)單吧:)


四,、發(fā)布我們的第一個(gè)程序

  第一個(gè)程序簡(jiǎn)單的返回HELLO WORLD!

HelloWorld.java

public class HelloWorld {
public String sayHello()
{
  return "HELLO WORLD!"; 

}

我們的第一種發(fā)布方式:

將HelloWorld.java拷貝到%TOMCAT_HOME%\webapps\axis下,,然后將其改名為HelloWorld.jws,這樣AXIS就自然將其發(fā)布了?,F(xiàn)在寫個(gè)客戶端程序訪問(wèn)一下:

TestClient.java

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

import javax.xml.rpc.ParameterMode;

public class TestClient
{
  public static void main(String [] args) throws Exception {
    
    String endpoint = "http://localhost:" +"8080"+ "/axis/HelloWorld.jws";//指明服務(wù)所在位置

    Service service = new Service(); //創(chuàng)建一個(gè)Service實(shí)例,注意是必須的,!
    Call   call   = (Call) service.createCall();//創(chuàng)建Call實(shí)例,,也是必須的!

  call.setTargetEndpointAddress( new java.net.URL(endpoint) );//為Call設(shè)置服務(wù)的位置

    call.setOperationName( "sayHello" );//注意方法名與HelloWorld.java中一樣??!

      String res = (String) call.invoke( new Object[] {} );//返回String,沒(méi)有傳入?yún)?shù)

                System.out.println( res );
  }
}

我的測(cè)試是在jbuilder2005中,,注意項(xiàng)目中要導(dǎo)入其自帶的AXIS包(當(dāng)然應(yīng)該把其中JAR文件替換一下),,可以看到程序返回了 "HELLO WORLD!"

可以看到在AXIS里發(fā)布服務(wù)其實(shí)是一件很容易的事,這是因?yàn)檫@個(gè)服務(wù)很簡(jiǎn)單的原因:)下面我們介紹第二種發(fā)布方式,,這是常用的,。

我們的第二種發(fā)布方式:

1、將HelloWorld.java編譯成HelloWorld.class,放到%TOMCAT_HOME%\webapps\axis\WEB-INF\classes

    下

2、在%TOMCAT_HOME%\webapps\axis\WEB-INF下新建deploy.wsdd文件,,即SOAP服務(wù)發(fā)布描述文件

  deploy.wsdd

<deployment xmlns="http://xml./axis/wsdd/" xmlns:java="" target="_blank">http://xml./axis/wsdd/providers/java">
  <service name="HelloWorld" provider="java:RPC">
    <parameter name="className" value="HelloWorld"/>
    <parameter name="allowedMethods" value="sayHello"/>
  </service>
</deployment>

在DOS下轉(zhuǎn)換目錄到%TOMCAT_HOME%\webapps\axis\WEB-INF,,命令:

java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.wsdd

你會(huì)發(fā)現(xiàn)目錄下多了一個(gè)server-config.wsdd文件,這就是AXIS的配置文件,,以后所有的服務(wù)發(fā)布描述都會(huì)在里面找到,。(當(dāng)然,你可以直接修改它,,不用再寫deploy.wsdd)然后打開(kāi)瀏覽器http://localhost:8080/axis/servlet/AxisServlet,,你就會(huì)看到你的服務(wù)已發(fā)布

注意:可以直接寫server-config.wsdd,如下:

<deployment xmlns="http://xml./axis/wsdd/" xmlns:java="http://xml./axis/wsdd/providers/java">
<handler type="java:org.apache.axis.handlers.http.URLMapper" name="URLMapper"/>   
   <service name="myService" provider="java:RPC">
        <parameter name="className" value="com.service.myService"/>
        <parameter name="allowedMethods" value="getusername"/>
    </service>
<transport name="http">
 <requestFlow>
    <handler type="URLMapper"/>
 </requestFlow>
</transport>
</deployment>

同樣用客戶端程序訪問(wèn)一下:(注意和上邊的差別!?。?/p>

HelloClient.java

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;

public class HelloClient
{
  public static void main(String [] args) throws Exception {

    String endpoint = "http://localhost:" +"8080"+ "/axis/services/HelloWorld";//注意,!差別僅僅在這里!,!

    Service service = new Service();
    Call   call   = (Call) service.createCall();
    call.setTargetEndpointAddress( new java.net.URL(endpoint) );
    call.setOperationName("sayHello" );

      String res = (String) call.invoke( new Object[] {} );

                System.out.println( res );
  }
}

好了,,相信你對(duì)AXIS已有了大致的了解。接下來(lái)將會(huì)涉及到傳參數(shù),、JAVABEAN對(duì)象,,及AXIS的安全問(wèn)題,下次再說(shuō)吧:)也歡迎和我,一個(gè)快樂(lè)的JAVA程序員,,聯(lián)系:)[email protected] 

第三種方式:

 1、編寫服務(wù)端程序server,,SayHello.java,,編譯server.SayHello.java

package server;

public class SayHello

{

    public String getName(String name)

    {

        return "hello "+name;

    }

}

  2、編寫wsdd文件

  deploy.wsdd文件內(nèi)容如下:

<deployment xmlns="http://xml./axis/wsdd/" xmlns:java="http://xml./axis/wsdd/providers/java">

 <service provider="java:RPC">

  <parameter value="server.SayHello.getName"/>

  <parameter value="*"/>

 </service>

</deployment>

  3,、發(fā)布服務(wù):

  編輯一個(gè)deploy.bat,,Axis_Lib為axis.jar路徑。內(nèi)容如下:

set Axis_Lib=D:\workspace\test\WEB-INF\lib

set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib%

set Axis_Servlet=http://localhost:8080/test/servlet/AxisServlet

%Java_Cmd% org.apache.axis.client.AdminClient -l%Axis_Servlet% deploy.wsdd

  執(zhí)行這個(gè)批處理文件,,這時(shí)候,,如果提示成功的話,訪問(wèn)http://localhost:8080/test/services 就會(huì)顯示服務(wù)列表,。

  4,、生成客戶端client stub文件

  在瀏覽器上訪問(wèn)服務(wù)器端的服務(wù),可以下載到WSDL文件,,通過(guò)Axis的相關(guān)工具,,可以自動(dòng)從WSDL文件中生成Web Service的客戶端代碼。

  編寫一個(gè)WSDL2Java.bat文件,,其內(nèi)容如下:

set Axis_Lib=D:\workspace\test\WEB-INF\lib

set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib%

set Output_Path=D:\workspace\test\src

set Package=server.SayHello

%Java_Cmd% org.apache.axis.wsdl.WSDL2Java -o%Output_Path% -p%Package% SayHello.wsdl

  執(zhí)行這個(gè)批處理文件就可以生成client stub.

  生成的stub client文件列表為:SayHello.java,,SayHelloService.java,SayHelloServiceLocator.java,SayHelloSoapBindingStub.java .

  5,、編寫客戶端程序,,編譯并執(zhí)行

  下面是一段junit測(cè)試客戶端代碼。

import java.net.URL;

import junit.framework.Test;

import junit.framework.TestCase;

import junit.framework.TestSuite;

public class TestWSClient extends TestCase {

    public TestWSClient(String string) {

        super(string);

    }

    public void SayHelloClient() throws Exception {

        SayHelloService service = new SayHelloServiceLocator();

        SayHello_PortType client = service.getSayHello() ;

        String retValue = client.getName("clientname");

        System.out.println(retValue);

    }

    public static Test suite() {

        TestSuite suite = new TestSuite();

        suite.addTest(new TestWSClient("SayHelloClient"));

        return suite;

    }

}


 

++++++++++++++++++++++++++++++++++++++
AXIS學(xué)習(xí)筆記(二)使用Handler來(lái)增強(qiáng)Web服務(wù)的功能

Handler的基本概念
J2EE Web 服務(wù)中的Handler技術(shù)特點(diǎn)非常像Servlet技術(shù)中的Filter,。我們知道,,在Servlet中,當(dāng)一個(gè)HTTP到達(dá)服務(wù)端時(shí),,往往要經(jīng)過(guò)多個(gè)Filter對(duì)請(qǐng)求進(jìn)行過(guò)濾,,然后才到達(dá)提供服務(wù)的Servlet,這些Filter的功能往往是對(duì)請(qǐng)求進(jìn)行統(tǒng)一編碼,,對(duì)用戶進(jìn)行認(rèn)證,,把用戶的訪問(wèn)寫入系統(tǒng)日志等。相應(yīng)的,,Web服務(wù)中的Handler通常也提供一下的功能: 

對(duì)客戶端進(jìn)行認(rèn)證,、授權(quán); 
把用戶的訪問(wèn)寫入系統(tǒng)日志,; 
對(duì)請(qǐng)求的SOAP消息進(jìn)行加密,,解密; 
為Web Services對(duì)象做緩存,。 
SOAP消息Handler能夠訪問(wèn)代表RPC請(qǐng)求或者響應(yīng)的SOAP消息,。在JAX-RPC技術(shù)中,SOAP消息Handler可以部署在服務(wù)端,,也可以在客戶端使用,。 

下面我們來(lái)看一個(gè)典型的SOAP消息Handler處理順序: 
某個(gè)在線支付服務(wù)需要防止非授權(quán)的用戶訪問(wèn)或者撰改服務(wù)端和客戶端傳輸?shù)男畔ⅲ瑥亩褂孟⒄∕essage Digest)的方法對(duì)請(qǐng)求和響應(yīng)的SOAP消息進(jìn)行加密,。當(dāng)客戶端發(fā)送SOAP消⑹保?突Ф說(shuō)?andler把請(qǐng)求消息中的某些敏感的信息(如信用卡密碼)進(jìn)行加密,,然后把加密后的SOAP消息傳輸?shù)椒?wù)端;服務(wù)端的SOAP消息Handler截取客戶端的請(qǐng)求,,把請(qǐng)求的SOAP 消息進(jìn)行解密,,然后把解密后的SOAP消息派發(fā)到目標(biāo)的Web服務(wù)端點(diǎn)。 

Apache axis是我們當(dāng)前開(kāi)發(fā)Web服務(wù)的較好的選擇,,使用axisWeb服務(wù)開(kāi)發(fā)工具,,可以使用Handler來(lái)對(duì)服務(wù)端的請(qǐng)求和響應(yīng)進(jìn)行處理。典型的情況下,,請(qǐng)求傳遞如圖1所示,。 


圖1 SOAP消息的傳遞順序


在圖中,軸心點(diǎn)(pivot point)是Apache與提供程序功能相當(dāng)?shù)牟糠?,通過(guò)它來(lái)和目標(biāo)的Web服務(wù)進(jìn)行交互,,它通常稱為Provider。axis中常用的Provider有Java:RPC,java:MSG,,java:EJB,。一個(gè)Web服務(wù)可以部署一個(gè)或者多個(gè)Handler。 

Apache axis中的Handler體系結(jié)構(gòu)和JAX-RPC 1.0(JSR101)中的體系結(jié)構(gòu)稍有不同,,需要聲明的是,,本文的代碼在axis中開(kāi)發(fā),故需要在axis環(huán)境下運(yùn)行,。 

在axis環(huán)境下,,SOAP消息Handler必須實(shí)現(xiàn)org.apache.axis.Handler接口(在JAX-RPC 1.0規(guī)范中,SOAP消息Handler必須實(shí)現(xiàn)javax.xml.rpc.handler.Handler接口),,org.apache.axis.Handler接口的部分代碼如下: 

例程1 org.apache.axis.Handle的部分代碼


public interface Handler extends Serializable {
  public void init(); 
  public void cleanup();
  public void invoke(MessageContext msgContext) throws AxisFault ;

  public void onFault(MessageContext msgContext);
  public void setOption(String name, Object value);   
  public Object getOption(String name);
  
  public void setName(String name);   
  public String getName();   
  public Element getDeploymentData(Document doc);
  public void generateWSDL(MessageContext msgContext) throws AxisFault;
  …
}

為了提供開(kāi)發(fā)的方便,,在編寫Handler時(shí),只要繼承org.apache.axis.handlers. BasicHandler即可,,BasicHandler是Handler的一個(gè)模板,,我們看它的部分代碼: 

例程2 BasicHandler的部分代碼


public abstract class BasicHandler implements Handler {
  protected static Log log =
    LogFactory.getLog(BasicHandler.class.getName());
  protected Hashtable options;
  protected String name;
  //這個(gè)方法必須在Handler中實(shí)現(xiàn)。
public abstract void invoke(MessageContext msgContext) throws AxisFault;
public void setOption(String name, Object value) {
    if ( options == null ) initHashtable();
    options.put( name, value );
  }

}

BasicHandler中的(MessageContext msgContext)方法是Handler實(shí)現(xiàn)類必須實(shí)現(xiàn)的方法,,它通過(guò)MessageContext來(lái)獲得請(qǐng)求或者響應(yīng)的SOAPMessage對(duì)象,,然后對(duì)SOAPMessage進(jìn)行處理。 

在介紹Handler的開(kāi)發(fā)之前,,我們先來(lái)看一下目標(biāo)Web服務(wù)的端點(diǎn)實(shí)現(xiàn)類的代碼,,如例程3所示。 

例程3 目標(biāo)Web服務(wù)的端點(diǎn)實(shí)現(xiàn)類


package com.hellking.webservice;
public class HandleredService 
{
//一個(gè)簡(jiǎn)單的Web服務(wù)
public String publicMethod(String name)
{
return "Hello!"+name;
}
}
//另一個(gè)Web服務(wù)端點(diǎn):
package com.hellking.webservice;
public class OrderService 
{
    //web服務(wù)方法:獲得客戶端的訂單信息,,并且對(duì)訂單信息進(jìn)行對(duì)應(yīng)的處理,,
通常情況是把訂單的信息寫入數(shù)據(jù)庫(kù),然后可客戶端返回確認(rèn)信息,。
public String orderProduct(String name,String address,String item,int quantity,Card card)
{
String cardId=card.getCardId();
String cardType=card.getCardType();
String password=card.getPassword();
String rderInfo="name="+name+",address="+address+",item="+item+",quantity="+quantity+"
,cardId="+cardId+",cardType="+cardType+",password="+password;
System.out.println("這里是客戶端發(fā)送來(lái)的信息:");
System.out.println(orderInfo); 
return orderInfo;

}

下面我們分不同情況討論Handler的使用實(shí)例。

使用Handler為系統(tǒng)做日志

Handler為系統(tǒng)做日志是一種比較常見(jiàn)而且簡(jiǎn)單的使用方式,。和Servlet中的Filter一樣,,我們可以使用Handler來(lái)把用戶的訪問(wèn)寫入系統(tǒng)日志。下面我們來(lái)看日志Handler的具體代碼,,如例程4所示,。 

例程4 LogHandler的代碼


package com.hellking.webservice;

import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Date;

import org.apache.axis.AxisFault;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;

public class LogHandler extends BasicHandler {

  /**invoke,每一個(gè)handler都必須實(shí)現(xiàn)的方法,。
*/
  public void invoke(MessageContext msgContext) throws AxisFault
  {
    //每當(dāng)web服務(wù)被調(diào)用,,都記錄到log中。
    try {
        Handler handler = msgContext.getService();
        String filename = (String)getOption("filename");
        if ((filename == null) || (filename.equals("")))
          throw new AxisFault("Server.NoLogFile",
                      "No log file configured for the LogHandler!",
                        null, null);
        FileOutputStream fos = new FileOutputStream(filename, true);         
        PrintWriter writer = new PrintWriter(fos);         
        Integer counter = (Integer)handler.getOption("accesses");
        if (counter == null)
          counter = new Integer(0);
        
        counter = new Integer(counter.intValue() + 1);         
        Date date = new Date();
        msgContext.getMessage().writeTo(System.out);
      
        String result = "在"+date + ": Web 服務(wù) " +
                  msgContext.getTargetService() +
                  " 被調(diào)用,,現(xiàn)在已經(jīng)共調(diào)用了 " + counter + " 次.";
        handler.setOption("accesses", counter);         
        writer.println(result);         
        writer.close();
    } catch (Exception e) {
        throw AxisFault.makeFault(e);
    }
  }
}

前面我們說(shuō)過(guò),,Handler實(shí)現(xiàn)類必須實(shí)現(xiàn)invoke方法,invoke方法是Handler處理其業(yè)務(wù)的入口點(diǎn)。LogHandler的主要功能是把客戶端訪問(wèn)的Web服務(wù)的名稱和訪問(wèn)時(shí)間,、訪問(wèn)的次數(shù)記錄到一個(gè)日志文件中,。 

下面部署這個(gè)前面開(kāi)發(fā)的Web服務(wù)對(duì)像,然后為Web服務(wù)指定Handler,。編輯Axis_Home/WEB-INF/ server-config.wsdd文件,,在其中加入以下的內(nèi)容:

<service name="HandleredService" provider="java:RPC">
<parameter name="allowedMethods" value="*"/>
<parameter name="className" value="com.hellking.webservice.HandleredService"/>
<parameter name="allowedRoles" value="chen"/>
<beanMapping languageSpecificType="java:com.hellking.webservice.Card"
qname="card:card" xmlns:card="card"/>
<requestFlow>
<handler name="logging" type="java:com.hellking.webservice.LogHandler">
<parameter name="filename" value="c:\\MyService.log"/>
</handler>
</requestFlow>
</service>



</globalConfiguration>

<handler name="logging" type="java:com.hellking.webservice.LogHandler">
<parameter name="filename" value="c:\\MyService.log"/>
</handler>

<service name="HandleredService" provider="java:RPC">

<requestFlow>
<handler type="logging"/>
  …<!--在這里可以指定多個(gè)Handler-->
</requestFlow>
</service>


http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen

注意:這個(gè)URL需要根據(jù)具體情況改變。

在Sun Jul 06 22:42:03 CST 2003: Web 服務(wù) HandleredService 被調(diào)用,,現(xiàn)在已經(jīng)共調(diào)用了 1 次.
在Sun Jul 06 22:42:06 CST 2003: Web 服務(wù) HandleredService 被調(diào)用,,現(xiàn)在已經(jīng)共調(diào)用了 2 次.
在Sun Jul 06 22:42:13 CST 2003: Web 服務(wù) HandleredService 被調(diào)用,現(xiàn)在已經(jīng)共調(diào)用了 3 次.

使用Handler對(duì)用戶的訪問(wèn)認(rèn)證

使用Handler為用戶訪問(wèn)認(rèn)證也是它的典型使用,,通過(guò)它,,可以減少在Web服務(wù)端代碼中認(rèn)證的麻煩,同時(shí)可以在部署描述符中靈活改變用戶的訪問(wèn)權(quán)限,。 

對(duì)用戶認(rèn)證的Handler代碼如下:

例程5 認(rèn)證的Handler


package com.hellking.webservice;
import….

//此handler的目的是對(duì)用戶認(rèn)證,,只有認(rèn)證的用戶才能訪問(wèn)目標(biāo)服務(wù)。
public class AuthenticationHandler extends BasicHandler
{
/**invoke,,每一個(gè)handler都必須實(shí)現(xiàn)的方法,。
*/
public void invoke(MessageContext msgContext)throws AxisFault

    SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
if(provider==null)
{
  provider= new SimpleSecurityProvider();
        msgContext.setProperty("securityProvider", provider);
      }
    if(provider!=null)
    {       
      String userId=msgContext.getUsername();
      String password=msgContext.getPassword();
      
      //對(duì)用戶進(jìn)行認(rèn)證,如果authUser==null,,表示沒(méi)有通過(guò)認(rèn)證,,
拋出Server.Unauthenticated異常。
        org.apache.axis.security.AuthenticatedUser authUser 
= provider.authenticate(msgContext);
        if(authUser==null)
        throw new AxisFault("Server.Unauthenticated", 
Messages.getMessage("cantAuth01", userId), null,null);
        //用戶通過(guò)認(rèn)證,,把用戶的設(shè)置成認(rèn)證了的用戶,。
        msgContext.setProperty("authenticatedUser", authUser);
    } 
  }
}

在AuthenticationHandler代碼里,它從MessageContext中獲得用戶信息,,然后進(jìn)行認(rèn)證,,如果認(rèn)證成功,那么就使用msgContext.setProperty("authenticatedUser", authUser)方法把用戶設(shè)置成認(rèn)證了的用戶,,如果認(rèn)證不成功,,那么就拋出Server.Unauthenticated異常,。 

部署這個(gè)Handler,,同樣,,在server-config里加入以下的內(nèi)容:

<handler name="authen" type="java:com.hellking.webservice.AuthenticationHandler"/>

<service name="HandleredService" provider="java:RPC">
<parameter name="allowedRoles" value="chen"/>

</service>

WEB-INF/users.lst文件中加入以下用戶:

hellking hellking
chen chen

http://127.0.0.1:8080/handler/services/HandleredService?wsdl&method=publicMethod&name=chen

將會(huì)提示輸入用戶名和密碼,如圖2所示,。

圖2 訪問(wèn)web服務(wù)時(shí)的驗(yàn)證 

如果客戶端是應(yīng)用程序,,那么可以這樣在客戶端設(shè)置用戶名和密碼:

例程6 在客戶端設(shè)置用戶名和密碼


http://127.0.0.1:808
String endpointURL = "http://127.0.0.1:8080/handler/services/HandleredService?wsdl";         
        Service service = new Service();
        Call   call   = (Call) service.createCall();
        call.setTargetEndpointAddress( new java.net.URL(endpointURL) );
        call.setOperationName( new
QName("HandleredService", "orderProduct") );//設(shè)置操作的名稱。
        //由于需要認(rèn)證,,故需要設(shè)置調(diào)用的用戶名和密碼,。
        call.getMessageContext().setUsername("chen");
        call.getMessageContext().setPassword("chen");       

使用Handler對(duì)用戶的訪問(wèn)授權(quán)

對(duì)于已經(jīng)認(rèn)證了的用戶,,有時(shí)在他們操作某個(gè)特定的服務(wù)時(shí),還需要進(jìn)行授權(quán),,只有授權(quán)的用戶才能繼續(xù)進(jìn)行操作,。我們看對(duì)用戶進(jìn)行授權(quán)的Handler的代碼。 

例程7 對(duì)用戶進(jìn)行授權(quán)的代碼


package com.hellking.webservice;

import…

//此handler的目的是對(duì)認(rèn)證的用戶授權(quán),,只有授權(quán)的用戶才能訪問(wèn)目標(biāo)服務(wù),。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一個(gè)handler都必須實(shí)現(xiàn)的方法,。
*/
public void invoke(MessageContext msgContext)
    throws AxisFault
  {
    
    AuthenticatedUser user = (AuthenticatedUser)msgContext.getProperty("authenticatedUser");
    if(user == null)
        throw new AxisFault("Server.NoUser", Messages.getMessage("needUser00"), null, null);
    String userId = user.getName();
    Handler serviceHandler = msgContext.getService();
    if(serviceHandler == null)
        throw new AxisFault(Messages.getMessage("needService00"));
    String serviceName = serviceHandler.getName();
    String allowedRoles = (String)serviceHandler.getOption("allowedRoles");
    if(allowedRoles == null)
    {       
        return;
    }
    SecurityProvider provider = (SecurityProvider)msgContext.getProperty("securityProvider");
    if(provider == null)
        throw new AxisFault(Messages.getMessage("noSecurity00"));
    for(StringTokenizer st = new StringTokenizer(allowedRoles, ","); st.hasMoreTokens();)
    {
        String thisRole = st.nextToken();
        if(provider.userMatches(user, thisRole))
        {
          return;//訪問(wèn)授權(quán)通過(guò),。
        }
    }
    //沒(méi)有通過(guò)授權(quán),不能訪問(wèn)目標(biāo)服務(wù),,拋出Server.Unauthorized異常,。
    throw new AxisFault("Server.Unauthorized", 
Messages.getMessage("cantAuth02", userId, serviceName), null, null);
  }   
}


在service-config.wsdd文件中,我們?yōu)閃eb服務(wù)指定了以下的用戶:

<parameter name="allowedRoles" value="chen,hellking"/>


provider.userMatches(user, thisRole)將匹配允許訪問(wèn)Web服務(wù)的用戶,,如果匹配成功,,那么授權(quán)通過(guò),如果沒(méi)有授權(quán)成功,,那么拋出Server.Unauthorized異常,。 

使用Handler對(duì)SOAP消息進(jìn)行加密、解密

由于SOAP消息在HTTP協(xié)議中傳輸,,而HTTP協(xié)議的安全度是比較低的,,怎么保證信息安全到達(dá)對(duì)方而不泄漏或中途被撰改,將是Web服務(wù)必須解決的問(wèn)題,。圍繞Web服務(wù)的安全,,有很多相關(guān)的技術(shù),比如WS-Security,,WS-Trace等,,另外,還有以下相關(guān)技術(shù): 

XML Digital Signature(XML數(shù)字簽名) 
XML Encryption (XML加密) 
XKMS (XML Key Management Specification) 
XACML (eXtensible Access Control Markup Language) 
SAML (Secure Assertion Markup Language) 
ebXML Message Service Security 
Identity Management & Liberty Project 
不管使用什么技術(shù),,要使信息安全到達(dá)對(duì)方,,必須把它進(jìn)行加密,然后在對(duì)方收到信息后解密,。為了提供開(kāi)發(fā)的方便,可以使用Handler技術(shù),,在客戶端發(fā)送信息前,,使用客戶端的Handler對(duì)SOAP消息中的關(guān)鍵信息進(jìn)行加密;在服務(wù)端接收到消息后,,有相應(yīng)的Handler把消息進(jìn)行解密,,然后才把SOAP消息派發(fā)到目標(biāo)服務(wù),。 

下面我們來(lái)看一個(gè)具體的例子。加入使用SOAP消息發(fā)送訂單的信息,,訂單的信息如下:

例程8 要發(fā)送的訂單SOAP消息

<soap-env:Envelope xmlns:soap-env="" target="_blank">http://schemas./soap/envelope/">
  <soap-env:Header/>
  <soapenv:Body>
  <ns1:orderProduct soapenv:encodingStyle="http://schemas./soap/encod
ing/" xmlns:ns1="HandleredService">
  <arg0 xsi:type="xsd:string">hellking</arg0>
  <arg1 xsi:type="xsd:string">beijing</arg1>
  <arg2 xsi:type="xsd:string">music-100</arg2>
  <arg3 xsi:type="xsd:int">10</arg3>
  <arg4 href="#id0"/>
  </ns1:orderProduct>
  <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmls
oap.org/soap/encoding/" xsi:type="ns2:card" xmlns:soapenc="http://schemas.xmlsoa
p.org/soap/encoding/" xmlns:ns2="card">
  
    <cardId xsi:type="xsd:string">234230572</cardId>
          
    <cardType xsi:type="xsd:string">visa</cardType>
          
    <password xsi:type="xsd:string">234kdsjf</password>
  </multiRef>
</soapenv:Body>
  </soap-env:Envelope>

    


上面的黑體字是傳輸?shù)拿舾行畔?,故需要加密。我們可以使用Message Digest之類的方法進(jìn)行加密,。加密之后的信息結(jié)構(gòu)如下: 

例程9 把SOAP消息某些部分加密


<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope …
<soapenv:Body>
<ns1:orderProduct …>
  …
  <arg4 href="#id0"/>
</ns1:orderProduct>
<multiRef …>
  <ns3:EncryptedData xmlns:ns3="" target="_blank">http://www./2000/11/temp-xmlenc">
  <ns3:DigestMethod Algorithm="http://www./2000/09/xmldsig#sha1"/>
  <ns3:DigestValue>rO0ABXQAkyA8Y2FyZ…….
</ns3:DigestValue>
  </ns3:EncryptedData>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>


圖3是使用Handler對(duì)SOAP消息進(jìn)行加密,、解密后,SOAP消息在傳遞過(guò)程中結(jié)構(gòu)的改變,。 


圖3 SOAP消息的加密和解密 

從上圖可以看出,,通過(guò)使用加密、解密的Handler,,可以確保消息的安全傳遞,。進(jìn)一步說(shuō),如果把這種Handler做成通用的組件,,那么就可以靈活地部署到不同的服務(wù)端和客戶端,。 

客戶端的Handler的功能是把SOAP消息使用一定的規(guī)則加密,假如使用Message Digest加密方式,,那么可以這樣對(duì)敏感的信息加密: 

例程10 對(duì)SOAP消息的敏感部分加密


      SOAPElement ele= soapBodyElement.addChildElement(envelope.createName
("EncryptedData","","http://www./2000/11/temp-xmlenc")); 
ele.addChildElement("DigestMethod").addAttribute(envelope.createName
("Algorithm"),"http://www./2000/09/xmldsig#sha1");
  
  byte[] digest=new byte[100];
  ByteArrayOutputStream out=new ByteArrayOutputStream (100);
  MessageDigest md = MessageDigest.getInstance("SHA");
  ObjectOutputStream oos = new ObjectOutputStream(out);
  //要加密的信息
  String data = " <cardId xsi:type='xsd:string'>234230572
                </cardId><cardType xsi:type='xsd:string'>visa</cardType>
                <password   xsi:type='xsd:string'>234kdsjf</password>";

  byte buf[] = data.getBytes();
  md.update(buf);
  oos.writeObject(data);
  oos.writeObject(md.digest()); 
  digest=out.toByteArray();
  out.close();     
    ele.addChildElement("DigestValue").addTextNode(new 
sun.misc.BASE64Encoder().encode(digest));//對(duì)加密的信息編碼

在客戶端發(fā)送出SOAP消息時(shí),,客戶端的Handler攔截發(fā)送的SOAP消息,然后對(duì)它們進(jìn)行加密,,最后把加密的信息傳送到服務(wù)端,。

服務(wù)端接收到加密的信息后,解密的Handler會(huì)把對(duì)應(yīng)的加密信息解密,。服務(wù)端Handler代碼如例程11所示,。 

例程11 服務(wù)端解密Handler


package com.hellking.webservice;
import…
//此handler的目的是把加密的SOAP消息解密成目標(biāo)服務(wù)可以使用的SOAP消息。
public class MessageDigestHandler extends BasicHandler
{
/**invoke,,每一個(gè)handler都必須實(shí)現(xiàn)的方法,。
*/
public void invoke(MessageContext msgContext)throws AxisFault
{
try
{   
  //從messageContext例取得SOAPMessage對(duì)象。
  SOAPMessage msg=msgContext.getMessage();
  SOAPEnvelope env=msg.getSOAPPart().getEnvelope();
  Iterator it=env.getBody().getChildElements();   
  SOAPElement multi=null;
  while(it.hasNext())
  {
  multi=(SOAPElement)it.next();//multi是soapbody的最后一個(gè)child,。
  }
  String value="";//value表示加密后的值,。
  SOAPElement digestValue=null;
  Iterator it2=multi.getChildElements();
  while(it2.hasNext())
  {
  SOAPElement temp=(SOAPElement)it2.next();
  Iterator it3=temp.getChildElements(env.createName("DigestValue",
"ns3","http://www./2000/11/temp-xmlenc"));
  if(it3.hasNext())
  value=((SOAPElement)it3.next()).getValue();//獲得加密的值   
  }   
  //把加密的SOAPMessage解密成目標(biāo)服務(wù)可以調(diào)用的SOAP消息。
  SOAPMessage   msg2=convertMessage(msg,this.decrypte(value));
  msgContext.setMessage(msg2);     
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }     

//這個(gè)方法是把加密的數(shù)據(jù)進(jìn)行解密,,返回明文,。
public String decrypte(String value)
{
String data=null;
try
{
  ByteArrayInputStream fis = new 
ByteArrayInputStream(new sun.misc.BASE64Decoder().decodeBuffer(value));
  ObjectInputStream ois = new ObjectInputStream(fis);
  Object o = ois.readObject();
  if (!(o instanceof String)) {
  System.out.println("Unexpected data in string");
  System.exit(-1);
  }
  data = (String) o;
  System.out.println("解密后的值:" + data);
  o = ois.readObject();
  if (!(o instanceof byte[])) {
  System.out.println("Unexpected data in string");
  System.exit(-1);
  }   
  byte origDigest[] = (byte []) o;
  MessageDigest md = MessageDigest.getInstance("SHA");
  md.update(data.getBytes());
}
      …
return data;
}
  //把解密后的信息重新組裝成服務(wù)端能夠使用的SOAP消息。
public SOAPMessage convertMessage(SOAPMessage msg,String data)
{   
  ….
}
}     

可以看出,,服務(wù)端解密的Handler和客戶端加密的Handler的操作是相反的過(guò)程,。

總結(jié)

通過(guò)以上的討論,相信大家已經(jīng)掌握了Handler的基本使用技巧,??梢钥闯?,通過(guò)使用Handler,可以給Web服務(wù)提供一些額外的功能,。在實(shí)際的開(kāi)發(fā)中,,我們可以開(kāi)發(fā)出一些通用的Handler,然后通過(guò)不同的搭配方式把它們部署到不同的Web服務(wù)中,。 
 
+++++++++++++++++++++++++++++++++++++++
AXIS學(xué)習(xí)筆記(三)(建立安全的AXIS服務(wù)上) 
ronghao100 原創(chuàng)

 在前面的文章中,,我們實(shí)現(xiàn)了最簡(jiǎn)單的AXIS服務(wù)。現(xiàn)在我們一起來(lái)討論一下Web服務(wù)的安全問(wèn)題,。
根據(jù)應(yīng)用的對(duì)安全要求的級(jí)別不同,,可以采用不同的方式來(lái)實(shí)現(xiàn)安全性,以下是目前最常用的一些實(shí)現(xiàn)方式(從低到高排列):
  1,、J2EE Web應(yīng)用默認(rèn)的訪問(wèn)控制(數(shù)據(jù)是明文的),; 
  2、使用axis的Handler進(jìn)行訪問(wèn)控制(數(shù)據(jù)是明文的),; 
  3,、使用Servlet過(guò)濾器(Filter)進(jìn)行訪問(wèn)控制(數(shù)據(jù)是明文的); 
  4,、使用SSL/HTTPS協(xié)議來(lái)傳輸(加密的數(shù)據(jù)傳輸協(xié)議),; 
  5、使用WS-Security規(guī)范對(duì)信息進(jìn)行加密與身份認(rèn)證(數(shù)據(jù)被加密傳輸),。
我們僅討論第2,、4、5種實(shí)現(xiàn)方式,。在此之前我們先來(lái)了解一下AXIS自帶的一個(gè)工具SOAPMonitor,。
一、SOAPMonitor的使用
打開(kāi)http://localhost:8080/axis/進(jìn)入AXIS的主頁(yè)面,,你會(huì)看見(jiàn):
  SOAPMonitor-[disabled by default for security reasons] ,,默認(rèn)狀態(tài)下其是不可用的,現(xiàn)在我們就來(lái)激活它,。
  
1,、到目錄%TOMCAT_HOME%\webapps\axis下,你會(huì)找到SOAPMonitorApplet.java,,在命令行中編譯它:
    javac -classpath %AXIS_HOME%\lib\axis.jar SOAPMonitorApplet.java
  編譯完之后你會(huì)看見(jiàn)目錄下多了很多CLASS文件,,它們的名字是SOAPMonitorApplet*.class

2、在目錄%TOMCAT_HOME%\webapps\axis\WEB-INF下打開(kāi)server-config.wsdd文件,,將下面的兩部分代碼直
  接加入其中相應(yīng)的位置
  第一部分:
    <handler name="soapmonitor"   type="java:org.apache.axis.handlers.SOAPMonitorHandler">
    <parameter name="wsdlURL"   value="/axis/SOAPMonitorService-impl.wsdl"/>
    <parameter name="namespace"   value="" target="_blank">http:///wsdl/2001/12/SOAPMonitorService-impl.wsdl"/>
    <parameter name="serviceName" value="SOAPMonitorService"/>
    <parameter name="portName" value="Demo"/>
    </handler>
  第二部分:
    <service name="SOAPMonitorService" provider="java:RPC">
    <parameter name="allowedMethods" value="publishMessage"/>
    <parameter name="className"   value="org.apache.axis.monitor.SOAPMonitorService"/>
    <parameter name="scope" value="Application"/>
    </service>

3,、選擇你要監(jiān)控的服務(wù)
  以上次的HelloWorld服務(wù)為例,在server-config.wsdd中你會(huì)找到這段代碼
  <service name="HelloWorld" provider="java:RPC">
    <parameter name="allowedMethods" value="sayHello"/>
    <parameter name="className" value="HelloWorld"/>
  </service>
  在這段代碼中加入以下的代碼:
  <requestFlow>
    <handler type="soapmonitor"/>
  </requestFlow>
  <responseFlow>
    <handler type="soapmonitor"/>
  </responseFlow>
  最后的樣子是:
  <service name="HelloWorld" provider="java:RPC">
  <requestFlow>
    <handler type="soapmonitor"/>
  </requestFlow>
  <responseFlow>
    <handler type="soapmonitor"/>
  </responseFlow>
  <parameter name="allowedMethods" value="sayHello"/>
  <parameter name="className" value="HelloWorld"/>
  </service>
  這樣HelloWorld服務(wù)就被監(jiān)控了
  
4,、啟動(dòng)Tomcat,打開(kāi)http://localhost:8080/axis/SOAPMonitor,,你就會(huì)看到Applet界面,在
  jbuilder2005中運(yùn)行我們上次寫的客戶端程序 TestClient.java,。OK,!你會(huì)在Applet界面看
  見(jiàn)客戶端與服務(wù)器端互發(fā)的XML內(nèi)容,注意這里是明文,!
  
二,、使用axis的Handler進(jìn)行訪問(wèn)控制(對(duì)安全要求不高時(shí)推薦)
  axis為Web服務(wù)的訪問(wèn)控制提供了相關(guān)的配置描述符,并且提供了一個(gè)訪問(wèn)控制的簡(jiǎn)單 Handler,。默認(rèn)情況下,,你只要在配置描述符中添加用戶,然后在Web服務(wù)器的部署描述符中自動(dòng)允許的角色即可,。

1,、在axis的配置文件users.lst(位于WEB-INF目錄下)中添加一個(gè)用戶,如"ronghao1111",,表示
  用戶名為ronghao,,密碼為1111。
  
2,、把例HelloWorld的Web服務(wù)重新部署(新加的部分已標(biāo)出)
  <service name="HelloWorld" provider="java:RPC">
  <requestFlow>
    <handler type="soapmonitor"/>
    <handler type="Authenticate"/> //新加的AXIS自帶的Handler
  </requestFlow>
  <responseFlow>
    <handler type="soapmonitor"/>
  </responseFlow>
  <parameter name="allowedMethods" value="sayHello"/>
  <parameter name="allowedRoles" value="ronghao"/>   //注意,,這里是新加的部分!
  <parameter name="className" value="HelloWorld"/>
  </service>
在這個(gè)部署描述符中,,指定HelloWorld服務(wù)只能被ronghao訪問(wèn)
  
3,、修改客戶端程序 TestClient.java,增加訪問(wèn)用戶名,、密碼(新加的部分已標(biāo)出)
  TestClient.java

import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.rpc.ParameterMode;

public class TestClient
{
  public static void main(String [] args) throws Exception {
  String endpoint = "http://localhost:" +"8080"+ "/axis/HelloWorld";

    Service service = new Service(); 
    Call   call   = (Call) service.createCall();
    call.getMessageContext().setUsername("ronghao");// 用戶名,。
    call.getMessageContext().setPassword("1111");//   密碼
  call.setTargetEndpointAddress( new java.net.URL(endpoint) );

  call.setOperationName( "sayHello" );
  String res = (String) call.invoke( new Object[] {} );

  System.out.println( res );
  }
}
執(zhí)行TestClient,能夠順利訪問(wèn)Web服務(wù),;如果修改用戶名或者密碼,,那么就不能訪問(wèn) 。同樣,,
你在http://localhost:8080/axis/SOAPMonitor中看到的請(qǐng)求和響應(yīng)的XML是明文,!

三、使用SSL/HTTPS協(xié)議來(lái)傳輸
  Web服務(wù)也可以使用SSL作為傳輸協(xié)議,。雖然JAX-RPC并沒(méi)有強(qiáng)制規(guī)定是否使用SSL協(xié)議,,但在tomcat
  下使用HTTPS協(xié)議。
1,、使用JDK自帶的工具創(chuàng)建密匙庫(kù)和信任庫(kù),。

1)通過(guò)使用以下的命令來(lái)創(chuàng)建服務(wù)器端的密匙庫(kù):
  keytool -genkey -alias Server -keystore server.keystore -keyalg RSA
輸入keystore密碼: changeit
您的名字與姓氏是什么?
[Unknown]: Server
您的組織單位名稱是什么,?
[Unknown]: ec
您的組織名稱是什么,?
[Unknown]: ec
您所在的城市或區(qū)域名稱是什么,?
[Unknown]: beijing
您所在的州或省份名稱是什么?
[Unknown]: beijing
該單位的兩字母國(guó)家代碼是什么
[Unknown]: CN
CN=Server, OU=ec, O=ec, L=beijing, ST=beijing, C=CN 正確嗎,?
[否]: y

輸入<Server>的主密碼
    (如果和 keystore 密碼相同,,按回車):
  以上命令執(zhí)行完成后,將獲得一個(gè)名為server.keystore的密匙庫(kù),。
  
2)生成客戶端的信任庫(kù),。首先輸出RSA證書(shū):
keytool -export -alias Server -file test_axis.cer -storepass changeit -keystore server.keystore
然后把RSA證書(shū)輸入到一個(gè)新的信任庫(kù)文件中。這個(gè)信任庫(kù)被客戶端使用,,被用來(lái)驗(yàn)證服務(wù)器端的身份,。
keytool -import -file test_axis.cer -storepass changeit -keystore client.truststore -alias serverkey -noprompt
以上命令執(zhí)行完成后,將獲得一個(gè)名為client.truststore的信任庫(kù),。

3)同理生成客戶端的密匙庫(kù)client.keystore和服務(wù)器端的信任庫(kù)server.truststore.方便起見(jiàn)給出.bat文件
  gen-cer-store.bat內(nèi)容如下:
  set SERVER_DN="CN=Server, OU=ec, O=ec, L=BEIJINGC, S=BEIJING, C=CN"
  set CLIENT_DN="CN=Client, OU=ec, O=ec, L=BEIJING, S=BEIJING, C=CN"
  set KS_PASS=-storepass changeit
  set KEYINFO=-keyalg RSA

  keytool -genkey -alias Server -dname %SERVER_DN% %KS_PASS% -keystore server.keystore %KEYINFO% -keypass changeit
  keytool -export -alias Server -file test_axis.cer %KS_PASS% -keystore server.keystore
  keytool -import -file test_axis.cer %KS_PASS% -keystore client.truststore -alias serverkey -noprompt

  keytool -genkey -alias Client -dname %CLIENT_DN% %KS_PASS% -keystore client.keystore %KEYINFO% -keypass changeit
  keytool -export -alias Client -file test_axis.cer %KS_PASS% -keystore client.keystore
  keytool -import -file test_axis.cer %KS_PASS% -keystore server.truststore -alias clientkey -noprompt
  
好的,,現(xiàn)在我們就有了四個(gè)文件:server.keystore,server.truststore,,client.keystore,,client.truststore

2、更改Tomcat的配置文件(server.xml),,增加以下部署描述符:(其實(shí)里面有,,只是被注釋掉了)
    <Connector port="8440" 
          maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
          enableLookups="false" disableUploadTimeout="true"
          acceptCount="100" scheme="https" secure="true"
          clientAuth="true" keystoreFile="f:\server.keystore" keystorePass="changeit"
          truststoreFile="f:\server.truststore" truststorePass="changeit"
          sslProtocol="TLS" />

3、把HelloWorld重新部署一次,,在server-config.wsdd中修改如下部署代碼,。(還原了而已)
  <service name="HelloWorld" provider="java:RPC">
  <requestFlow>
    <handler type="soapmonitor"/>
  </requestFlow>
  <responseFlow>
    <handler type="soapmonitor"/>
  </responseFlow>
  <parameter name="allowedMethods" value="sayHello"/>
  <parameter name="className" value="HelloWorld"/>
  </service>
  
4、修改客戶端程序 TestClient.java(修改的部分已標(biāo)出)

  public class TestClient
{
  public static void main(String [] args) throws Exception {
  String endpoint = "https://localhost:" +"8440"+ "/axis/HelloWorld";//注意區(qū)別在這里,!https,!

    Service service = new Service(); 
    Call   call   = (Call) service.createCall();
  call.setTargetEndpointAddress( new java.net.URL(endpoint) );

  call.setOperationName( "sayHello" );
  String res = (String) call.invoke( new Object[] {} );

  System.out.println( res );
  }
}

5、最后使用命令來(lái)執(zhí)行客戶端程序

java -cp %AXISCLASSPATH%
  -Djavax.net.ssl.keyStore=client.keystore 
  -Djavax.net.ssl.keyStorePassword=changeit 
  -Djavax.net.ssl.trustStore=client.truststore 
  TestClient 
 

+++++++++++++++++++++++++++++++++++++++
AXIS學(xué)習(xí)筆記(四)(建立安全的AXIS服務(wù)下) 
ronghao100 原創(chuàng) 

四,、使用WS-Security規(guī)范對(duì)信息進(jìn)行加密與身份認(rèn)證
  我們打算用Handler結(jié)合WSSecurity實(shí)現(xiàn)Web服務(wù)安全(Handler的有關(guān)內(nèi)容請(qǐng)參閱AXIS學(xué)習(xí)筆記(二))
  設(shè)想流程:用WSClientRequestHandler.java位于客戶端對(duì)客戶端發(fā)出的XML文檔進(jìn)行加密
          WSServerRequestHandler.java位于服務(wù)器端對(duì)客戶端發(fā)出的加密后的XML文檔進(jìn)行解密
          WSServerResponseHandler.java位于服務(wù)器端對(duì)服務(wù)器端返回的XML文檔進(jìn)行加密
          WSClientResponseHandler.java位于客戶端對(duì)服務(wù)器端返回的XML文檔進(jìn)行解密
          
1,、使用ISNetworks安全提供者,ISNetworks實(shí)現(xiàn)了RSA加密,、解密算法,。
  當(dāng)然,你也可以使用其它的安全提供者,,并且可以使用不同的加密算法,。
  ISNetworks相關(guān)包ISNetworksProvider.jar??截惖?TOMCAT_HOME%   \webapps\axis\WEB-INF\lib
  
2,、Trust Services Integration Kit提供了一個(gè)WS-Security實(shí)現(xiàn)。你可以從http://www.獲得相關(guān)庫(kù)文件,分別是ws-security.jar和tsik.jar,。ws-security.jar中包含一個(gè)WSSecurity類,,我們使用它來(lái)對(duì)XML進(jìn)行數(shù)字簽名和驗(yàn)證,加密與解密,。同樣拷貝到%TOMCAT_HOME%\webapps\axis\WEB-INF\lib

3,、創(chuàng)建密匙庫(kù)和信任庫(kù)。(見(jiàn)上文,,一模一樣!)
  
4,、框架結(jié)構(gòu)
  WSClientHandler.java //基類,,包含了一些公用方法
  WSClientRequestHandler.java //繼承于WSClientHandler.java,調(diào)用WSHelper.java對(duì)客戶端發(fā)出的XML文檔進(jìn)行加密
  WSClientResponseHandler.java //繼承于WSClientHandler.java,,調(diào)用WSHelper.java對(duì)服務(wù)器端返回的XML文檔進(jìn)行解密
  WSServerHandler.java //基類,,包含了一些公用方法
  WSServerRequestHandler.java //繼承于WSServerHandler.java,調(diào)用WSHelper.java對(duì)客戶端發(fā)出的加密后的XML文檔進(jìn)行解密
  WSServerResponseHandler.java//繼承于WSServerHandler.java,,調(diào)用WSHelper.java對(duì)服務(wù)器端返回的XML文檔進(jìn)行加密
  WSHelper.java //核心類,,對(duì)SOAP消息簽名、加密,、解密,、身份驗(yàn)證
  MessageConverter.java //幫助類,Document,、SOAP消息互相轉(zhuǎn)換

5,、具體分析(在此強(qiáng)烈建議看一下tsik.jar的API)
  WSHelper.java 
  public class WSHelper {
    static String PROVIDER="ISNetworks";//JSSE安全提供者。
//添加JSSE安全提供者,,你也可以使用其它安全提供者,。只要支持DESede算法。這是程序里動(dòng)態(tài)加載還可以在JDK中靜態(tài)加載
    static
    {
      java.security.Security.addProvider(new com.isnetworks.provider.jce.ISNetworksProvider());
  }
  /**
  *對(duì)XML文檔進(jìn)行數(shù)字簽名,。
  */
    public static void sign(Document doc, String keystore, String storetype,
                                String storepass, String alias, String keypass) throws Exception {
          FileInputStream fileInputStream = new FileInputStream(keystore);
          java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
          keyStore.load(fileInputStream, storepass.toCharArray());
          PrivateKey key = (PrivateKey)keyStore.getKey(alias, keypass.toCharArray());
          X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
          SigningKey sk = SigningKeyFactory.makeSigningKey(key);
          KeyInfo ki = new KeyInfo();
          ki.setCertificate(cert);
          WSSecurity wSSecurity = new WSSecurity();//ws-security.jar中包含的WSSecurity類
          wSSecurity.sign(doc, sk, ki);//簽名,。


    }
  /**
  *對(duì)XML文檔進(jìn)行身份驗(yàn)證。
  */
    public static boolean verify(Document doc, String keystore, String storetype,
                                String storepass) throws Exception {
          FileInputStream fileInputStream = new FileInputStream(keystore);
          java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
          keyStore.load(fileInputStream, storepass.toCharArray());
          TrustVerifier verifier = new X509TrustVerifier(keyStore);
          WSSecurity wSSecurity = new WSSecurity();
          MessageValidity[] resa = wSSecurity.verify(doc, verifier, null,null);
          if (resa.length > 0)
                return resa[0].isValid();
          return false;
    }
  /**
  *對(duì)XML文檔進(jìn)行加密,。必須有JSSE提供者才能加密,。
  */
    public static void encrypt(Document doc, String keystore, String storetype,
                                String storepass, String alias) throws Exception {
          try
          {
          FileInputStream fileInputStream = new FileInputStream(keystore);
          java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
          keyStore.load(fileInputStream, storepass.toCharArray());
          X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
          PublicKey pubk = cert.getPublicKey();
          KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede",PROVIDER);
          keyGenerator.init(168, new SecureRandom());
          SecretKey key = keyGenerator.generateKey();
          KeyInfo ki = new KeyInfo();
          ki.setCertificate(cert);
          WSSecurity wSSecurity = new WSSecurity();
          //加密。
          wSSecurity.encrypt(doc, key, AlgorithmType.TRIPLEDES, pubk, AlgorithmType.RSA1_5, ki);
    }
    catch(Exception e)
    {
          e.printStackTrace();
    }
    }
  /**
  *對(duì)文檔進(jìn)行解密,。
  */
    public static void decrypt(Document doc, String keystore, String storetype,
                                String storepass, String alias, String keypass) throws Exception {
          FileInputStream fileInputStream = new FileInputStream(keystore);
          java.security.KeyStore keyStore = java.security.KeyStore.getInstance(storetype);
          keyStore.load(fileInputStream, storepass.toCharArray());
          PrivateKey prvk2 = (PrivateKey)keyStore.getKey(alias, keypass.toCharArray());

          WSSecurity wSSecurity = new WSSecurity();
          //解密,。

          wSSecurity.decrypt(doc, prvk2, null);
          WsUtils.removeEncryptedKey(doc);//從 WS-Security Header中刪除 EncryptedKey 元素
    }

    public static void removeWSSElements(Document doc) throws Exception {
          WsUtils.removeWSSElements(doc);// 刪除WSS相關(guān)的元素。
    }

}

  WSClientHandler.java
  //繼承自org.apache.axis.handlers.BasicHandler即AXIS內(nèi)在的
  public class WSClientHandler extends BasicHandler{
protected String keyStoreFile ;
protected String keyStoreType ="JKS";//默認(rèn)
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = "JKS";//默認(rèn)
protected String trustStorePassword ;
protected String certAlias ;

public void setInitialization(String keyStoreFile,String keyStoreType,String keyStorePassword,
          String keyAlias,String keyEntryPassword,String trustStoreFile,
          String trustStoreType,String trustStorePassword,String certAlias){
this.keyStoreFile=keyStoreFile;
this.keyStoreType=keyStoreType;
this.keyStorePassword=keyStorePassword;
this.keyAlias=keyAlias;
this.keyEntryPassword=keyEntryPassword;
this.trustStoreFile=trustStoreFile;
this.trustStoreType=trustStoreType;
this.trustStorePassword=trustStorePassword;
this.certAlias=certAlias;
}
public void setInitialization(String keyStoreFile,String keyStorePassword,
          String keyAlias,String keyEntryPassword,String trustStoreFile,
          String trustStorePassword,String certAlias){
this.keyStoreFile=keyStoreFile;
this.keyStorePassword=keyStorePassword;
this.keyAlias=keyAlias;
this.keyEntryPassword=keyEntryPassword;
this.trustStoreFile=trustStoreFile;
this.trustStorePassword=trustStorePassword;
this.certAlias=certAlias;
}
public void invoke(MessageContext messageContext) throws AxisFault {//在這個(gè)方法里對(duì)XML文檔進(jìn)行處理
  //do nothing now!
}
public void onFault(MessageContext msgContext) {
  System.out.println("處理錯(cuò)誤,,這里忽略,!");
    }
}

WSClientRequestHandler.java
public class WSClientRequestHandler extends WSClientHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
  try {

  SOAPMessage soapMessage = messageContext.getMessage();
  Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage); //soapMessage轉(zhuǎn)換為Document
  WSHelper.sign(doc, keyStoreFile, keyStoreType,keyStorePassword, keyAlias, keyEntryPassword); //數(shù)字簽名
  WSHelper.encrypt(doc, trustStoreFile, trustStoreType, trustStorePassword, certAlias); //加密
  soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc); 
//處理后的Document再轉(zhuǎn)換回soapMessage
  messageContext.setMessage(soapMessage);
  } catch (Exception e){
  System.err.println("在處理響應(yīng)時(shí)發(fā)生以下錯(cuò)誤: " + e);
    e.printStackTrace(); }
    }

WSClientResponseHandler.java
public class WSClientResponseHandler extends WSClientHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
  try {

        SOAPMessage soapMessage = messageContext.getCurrentMessage();
        Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage);

    WSHelper.decrypt(doc, keyStoreFile, keyStoreType,
                  keyStorePassword, keyAlias, keyEntryPassword);//解密

        WSHelper.verify(doc, trustStoreFile, trustStoreType, trustStorePassword);//驗(yàn)證
        WSHelper.removeWSSElements(doc);
        soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc);
        messageContext.setMessage(soapMessage);
  } catch (Exception e){
        e.printStackTrace();
        System.err.println("在處理響應(yīng)時(shí)發(fā)生以下錯(cuò)誤: " + e);
                }

    }
}   
  
  WSServerHandler.java 
  public class WSServerHandler extends BasicHandler{
protected String keyStoreFile ;
protected String keyStoreType ="JKS";//默認(rèn)
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = "JKS";//默認(rèn)
protected String trustStorePassword ;
protected String certAlias ;

public void invoke(MessageContext messageContext) throws AxisFault {
  //do nothing now!
}
public void onFault(MessageContext msgContext) {
  System.out.println("處理錯(cuò)誤,這里忽略!");
    }
public void init() { //初始化,,從配置文件server-config.wsdd中讀取屬性
  keyStoreFile = (String)getOption("keyStoreFile");
  if(( keyStoreFile== null) )
    System.err.println("Please keyStoreFile configured for the Handler!");
  trustStoreFile = (String)getOption("trustStoreFile");
  if(( trustStoreFile== null) )
  System.err.println("Please trustStoreFile configured for the Handler!");
  keyStorePassword = (String)getOption("keyStorePassword");
  if(( keyStorePassword== null) )
  System.err.println("Please keyStorePassword configured for the Handler!");
  keyAlias = (String)getOption("keyAlias");
  if(( keyAlias== null) )
  System.err.println("Please keyAlias configured for the Handler!");
  keyEntryPassword = (String)getOption("keyEntryPassword");
  if(( keyEntryPassword== null) )
  System.err.println("Please keyEntryPassword configured for the Handler!");
  trustStorePassword = (String)getOption("trustStorePassword");
  if(( trustStorePassword== null) )
  System.err.println("Please trustStorePassword configured for the Handler!");
  certAlias = (String)getOption("certAlias");
  if ((certAlias==null))
    System.err.println("Please certAlias configured for the Handler!");
  if ((getOption("keyStoreType")) != null)
    keyStoreType = (String)getOption("keyStoreType");
  if ((getOption("trustStoreType")) != null)
    trustStoreType = (String)getOption("trustStoreType");
  }
}       
  
  WSServerRequestHandler.java 
  public class WSServerRequestHandler extends WSServerHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
  try {
    SOAPMessage msg = messageContext.getCurrentMessage();
        Document doc = MessageConverter.convertSoapMessageToDocument(msg);
        System.out.println("接收的原始消息:");
      msg.writeTo(System.out);
    WSHelper.decrypt(doc, keyStoreFile, keyStoreType,
                  keyStorePassword, keyAlias, keyEntryPassword);//解密

        WSHelper.verify(doc, trustStoreFile, trustStoreType, trustStorePassword);//驗(yàn)證
        WSHelper.removeWSSElements(doc);
        msg = MessageConverter.convertDocumentToSOAPMessage(doc);
        System.out.println("懷原后的原始消息:");
        msg.writeTo(System.out);
        messageContext.setMessage(msg);
  } catch (Exception e){
        e.printStackTrace();
        System.err.println("在處理響應(yīng)時(shí)發(fā)生以下錯(cuò)誤: " + e);
                }

    }
}   
  
  WSServerResponseHandler.java
  public class WSServerResponseHandler extends WSServerHandler{
public void invoke(MessageContext messageContext) throws AxisFault {
  try {

  SOAPMessage soapMessage = messageContext.getMessage();
    System.out.println("返回的原始消息:");
      soapMessage.writeTo(System.out);
    Document doc = MessageConverter.convertSoapMessageToDocument(soapMessage);

    WSHelper.sign(doc, keyStoreFile, keyStoreType,
      keyStorePassword, keyAlias, keyEntryPassword);//數(shù)字簽名
    WSHelper.encrypt(doc, trustStoreFile, trustStoreType,//加密
    trustStorePassword, certAlias);

    soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc);
    System.out.println("返回的加密后的消息:");
    soapMessage.writeTo(System.out);
    messageContext.setMessage(soapMessage);
    } catch (Exception e){
    System.err.println("在處理響應(yīng)時(shí)發(fā)生以下錯(cuò)誤: " + e);
      e.printStackTrace();
      }

    }
}

6,、應(yīng)用
  為方便使用,把上述文件打包為ws-axis.jar,放入%TOMCAT_HOME%\webapps\axis\WEB-INF\lib
  
  1)把HelloWorld重新部署一次,,在server-config.wsdd中修改如下部署代碼,。
    <service name="HelloWorld" provider="java:RPC">
      <parameter name="allowedMethods" value="*"/>
      <parameter name="className" value="HelloWorld"/>
      <requestFlow>
      <handler type="soapmonitor"/>
      <handler type="java:com.ronghao.WSAxis.WSServerRequestHandler">
        <parameter name="keyStoreFile" value="f:\server.keystore"/>
        <parameter name="trustStoreFile" value="f:\server.truststore"/>
        <parameter name="keyStorePassword" value="changeit"/>
        <parameter name="keyAlias" value="Server"/>
        <parameter name="keyEntryPassword" value="changeit"/>
        <parameter name="trustStorePassword" value="changeit"/>
        <parameter name="certAlias" value="clientkey"/>
      </handler>
    </requestFlow>
    <responseFlow>
      <handler type="soapmonitor"/>
      <handler type="java:com.ronghao.WSAxis.WSServerResponseHandler">
        <parameter name="keyStoreFile" value="f:\server.keystore"/>
        <parameter name="trustStoreFile" value="f:\server.truststore"/>
        <parameter name="keyStorePassword" value="changeit"/>
        <parameter name="keyAlias" value="Server"/>
        <parameter name="keyEntryPassword" value="changeit"/>
        <parameter name="trustStorePassword" value="changeit"/>
        <parameter name="certAlias" value="clientkey"/>
      </handler>
    </responseFlow>
  </service>
  
  2)修改客戶端程序 TestClient.java(修改的部分已標(biāo)出,記著導(dǎo)入ws-axis.jar)
  import javax.xml.namespace.QName;
  import org.apache.axis.client.Call;
  import org.apache.axis.client.Service;
  import com.ronghao.WSAxis.*;
  
  public class WSSClient1
{
  public static void main(String [] args)
  {
    try {
          //服務(wù)端的url,,需要根據(jù)情況更改,。
        String endpointURL = "http://localhost:8080/axis/services/HelloWorld";
        Service svc = new Service();

        WSClientHandler handler=new WSClientRequestHandler();
//注意新加的HANDLER
        handler.setInitialization("f:/client.keystore","changeit","Client","changeit",
          "f:/client.truststore","changeit","serverkey");//初始化
        WSClientHandler handlee=new WSClientResponseHandler();
//注意新加的HANDLER
        handlee.setInitialization("f:/client.keystore","changeit","Client","changeit",
          "f:/client.truststore","changeit","serverkey");//初始化
              Call call =(Call)svc.createCall();
              call.setClientHandlers(handler,handlee);//添加Handler
              call.setTargetEndpointAddress(new java.net.URL(endpointURL));
              call.setOperationName(new QName("sayHello"));

              String result = (String) call.invoke( new Object [] {});
              System.out.println("the result"+result);

    } catch (Exception e) {
          e.printStackTrace();
    }
  }


}
  運(yùn)行的時(shí)候http://localhost:8080/axis/SOAPMonitor中看到的請(qǐng)求的XML就已加密!
  
總結(jié)
  這里對(duì)代碼的解釋是不夠的,,很多概念沒(méi)有提到,。建議你最好看tsik.jar和AXIS的API深入了解。另外對(duì)ws-axis.jar的加解密實(shí)現(xiàn)打算運(yùn)用apache的wss4j,相關(guān)網(wǎng)址http://ws./ws-fx/wss4j/,。不過(guò)這個(gè)東西也應(yīng)該夠用了暫時(shí),。所有的源文件在附件中附件:soapTest.zip(279K) 
 
++++++++++++++++++++++++++++++++++++++
AXIS學(xué)習(xí)筆記(五)( 在AXIS服務(wù)間傳遞JavaBean及其安全解決) 
ronghao100 原創(chuàng) 
              在AXIS服務(wù)間傳遞JavaBean及其安全解決
這是AXIS學(xué)習(xí)筆記的最后一篇。在前面我們討論了最簡(jiǎn)單的HelloWorld服務(wù),,客戶端并沒(méi)有向服務(wù)器端
傳遞參數(shù),,現(xiàn)在我們來(lái)傳傳JavaBean。當(dāng)然,,也可以傳遞你自己定義的JAVA類,,但那樣你必須自己創(chuàng)建
專門的XML序列化器和反序列化器;而對(duì)JavaBean,,AXIS提供了現(xiàn)成的序列化器,。(有人說(shuō):懶惰是程序員最大的美德,我喜歡,,所以我就傳傳JavaBean)

一,、服務(wù)器端
1、CLASS類兩個(gè)Order.class,OrderTest.class,,位于%TOMCAT_HOME%\webapps\axis\WEB-INF\classes下
  這兩個(gè)類都直接給出源碼,,不再說(shuō)明
  Order.java
  public class Order {
    private String id;
    private String name;
    public void setId(String id){
      this.id=id;
    }
    public String getId(){
      return id;
    }
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    }
    
  OrderTest.java
  public class OrderTest {
    public Order returnOrder(Order order){
    Order newOrder=new Order();
    if(order.getId().equals("1"))
      newOrder.setName("ronghao");
    else newOrder.setName("haorong");
    return newOrder;
    }
  }
  
2、修改服務(wù)器端配置文件server-config.wsdd
  在server-config.wsdd中相應(yīng)位置添加以下代碼
<service name="Order" provider="java:RPC">
  <parameter name="allowedMethods" value="returnOrder"/>
  <parameter name="className" value="OrderTest"/>
  <beanMapping languageSpecificType="java:Order" qname="ns1:Order" 
      xmlns:ns1="urn:BeanService"/>
</service>
可以看到和前面的發(fā)布服務(wù)代碼相比僅多了一行代碼
  <beanMapping languageSpecificType="java:Order" qname="ns1:Order" 
      xmlns:ns1="urn:BeanService"/>
  languageSpecificType屬性指定JavaBean類文件位置,例如:
  languageSpecificType="java:com.ronghao.axis.Order"
  qname屬性指定JavaBean類的名字
  其他是固定的,。
  
二,、客戶端
  客戶端類文件一個(gè)OrderClient.class,代碼如下(變化的部分加注釋):
  public class OrderClient
{

  public static void main(String args[])
    throws Exception
  {
    String endpoint = "http://localhost:8080/axis/services/Order"; //服務(wù)所在位置
    Order order=new Order();   //JavaBean
    order.setId("1");
    Service service = new Service();
    Call call = (Call)service.createCall();
    //注冊(cè)JavaBean,,注意和server-config.wsdd中的配置代碼比較
    QName qn = new QName("urn:BeanService", "Order");
    call.registerTypeMapping(Order.class, qn, new BeanSerializerFactory(Order.class, qn), 
                    new BeanDeserializerFactory(Order.class, qn));
    String name="no!";
    try
    {
        call.setTargetEndpointAddress(new URL(endpoint));
        //調(diào)用的服務(wù)器端方法
        call.setOperationName(new QName("Order", "returnOrder"));
        //設(shè)定傳入的參數(shù),,這里qn即Order.class
        call.addParameter("arg1", qn, ParameterMode.IN);
        //設(shè)定返回的參數(shù)是Order.class
        call.setReturnType(qn, Order.class);
        Order result = (Order)call.invoke(new Object[] {
          order
        });
        if(result != null)
          name = result.getName();
    }
    catch(Exception e)
    {
        System.err.println(e);
    }
    System.out.println(name);
  }
}
OK!運(yùn)行一下,,就可以看到返回了"ronghao",。

和上一篇文章一樣,,我們不容許在網(wǎng)絡(luò)中傳遞XML是明文,于是需要加密和驗(yàn)證,。這里我們繼續(xù)采用上次所講的框架,。(已打包成ws-axis.jar)

一、修改服務(wù)器端配置文件server-config.wsdd(和上一文章一模一樣,!不再羅嗦)
在server-config.wsdd中相應(yīng)位置添加以下代碼
      <requestFlow>
      <handler type="soapmonitor"/>
      <handler type="java:com.ronghao.WSAxis.WSServerRequestHandler">
        <parameter name="keyStoreFile" value="f:\server.keystore"/>
        <parameter name="trustStoreFile" value="f:\server.truststore"/>
        <parameter name="keyStorePassword" value="changeit"/>
        <parameter name="keyAlias" value="Server"/>
        <parameter name="keyEntryPassword" value="changeit"/>
        <parameter name="trustStorePassword" value="changeit"/>
        <parameter name="certAlias" value="clientkey"/>
      </handler>
    </requestFlow>
    <responseFlow>
      <handler type="soapmonitor"/>
      <handler type="java:com.ronghao.WSAxis.WSServerResponseHandler">
        <parameter name="keyStoreFile" value="f:\server.keystore"/>
        <parameter name="trustStoreFile" value="f:\server.truststore"/>
        <parameter name="keyStorePassword" value="changeit"/>
        <parameter name="keyAlias" value="Server"/>
        <parameter name="keyEntryPassword" value="changeit"/>
        <parameter name="trustStorePassword" value="changeit"/>
        <parameter name="certAlias" value="clientkey"/>
      </handler>
    </responseFlow>
    
二,、客戶端(區(qū)別就在這里,注意?。,。?br>首先在這里要說(shuō)一下,客戶端代碼編寫困擾了我很長(zhǎng)一段時(shí)間(整整一天),,因?yàn)樗⒉幌笪蚁胂蟮哪敲春?jiǎn)單,,當(dāng)然解決起來(lái)還是挺簡(jiǎn)單的:)問(wèn)題的解決經(jīng)歷了三個(gè)階段

第一階段:
  在這個(gè)階段我想當(dāng)然的在OrderClient.class中加入了如下代碼:
        WSClientHandler handler=new WSClientRequestHandler();//注意新加的HANDLER
        handler.setInitialization("f:/client.keystore","changeit","Client","changeit",
          "f:/client.truststore","changeit","serverkey");//初始化
        WSClientHandler handlee=new WSClientResponseHandler();//注意新加的HANDLER
        handlee.setInitialization("f:/client.keystore","changeit","Client","changeit",
          "f:/client.truststore","changeit","serverkey");//初始化
        call.setClientHandlers(handler,handlee);//添加Handler
  這個(gè)方法也是我在上一文章里介紹的,結(jié)果拋出以下異常:
  faultString: org.xml.sax.SAXException: Deserializing parameter
  'newProfileReturn': could not find deserializer for type
  {urn:BeanService Order}SerializableProfile
  也就是說(shuō)不能正常解析XML文件,,于是理所當(dāng)然的郁悶了,覺(jué)得代碼中肯定漏設(shè)了CALL的一個(gè)屬性,,于是查看AXIS的源代碼,,沒(méi)有結(jié)果!轉(zhuǎn)機(jī)出現(xiàn)在下面一行代碼,,在不斷的拋出異常中我修改了代碼
  將call.setClientHandlers(handler,handlee);改為
  call.setClientHandlers(null,null);
  結(jié)果程序還是拋出同樣的異常,,于是意識(shí)到這可能是AXIS的一個(gè)BUG,為證明這一點(diǎn),,我將下面的Handler初始化代碼刪除
        WSClientHandler handler=new WSClientRequestHandler();//注意新加的HANDLER
        handler.setInitialization("f:/client.keystore","changeit","Client","changeit",
          "f:/client.truststore","changeit","serverkey");//初始化
        WSClientHandler handlee=new WSClientResponseHandler();//注意新加的HANDLER
        handlee.setInitialization("f:/client.keystore","changeit","Client","changeit",
          "f:/client.truststore","changeit","serverkey");//初始化
  結(jié)果還是拋出同樣的異常,,果然是BUG!得到這個(gè)結(jié)論后去了apache AXIS主頁(yè),,在問(wèn)題列表中見(jiàn)到了完全一樣問(wèn)題的提交,,但沒(méi)有解答(暈!)
  最后得到了結(jié)論:call的setClientHandlers()方法只有當(dāng)call處理簡(jiǎn)單的數(shù)據(jù)類型,,如String,int等等才能正常使用,!
  (當(dāng)然,如果你對(duì)這個(gè)問(wèn)題有不同的見(jiàn)解,,歡迎和我聯(lián)系,。或許我錯(cuò)了,,但程序不運(yùn)行是真的:))
  
第二階段:
  開(kāi)始在google上找問(wèn)題的解決方法,,這也是我的習(xí)慣:)。找了一個(gè)類似問(wèn)題的討論,,地址如下:
  http://marc./?l=axis-user&m=111259980822735&w=2
  他們的解決方法是Handler繼承于javax.xml.rpc.handler.Handler,,然后在程序里動(dòng)態(tài)注冊(cè)而在我的ws-axis.jar里Handler繼承于org.apache.axis.handlers.BasicHandler。當(dāng)然,
  javax.xml.rpc.handler.Handler是org.apache.axis.handlers.BasicHandler的老爸,,但在程序里老爸和兒子之間卻不能很好的兼容,,這也許就是所謂的代溝?,?無(wú)奈中重新寫了Handler,但在運(yùn)行中卻拋出異常,,提示message在被invoke的時(shí)候已被更改。我靠,,Handler的作用就是來(lái)更改message的?。∵@是什么世道,!
  我知道很多程序采用的就是這種方法,,但我好象怎么修改都拋出上述異常。
  
第三階段
  既然在程序里動(dòng)態(tài)注冊(cè)Handler行不通,,于是決定寫個(gè)單獨(dú)的配置文件來(lái)注冊(cè)Handler,。如果這種方法不幸失敗就返回第二階段。好馬為什么不吃回頭草,?,?
1、ws-axis.jar中修改WSClientHandler.class,修改后如下,,我想你一看就明白為何修改

public class WSClientHandler extends BasicHandler{
protected String keyStoreFile ;
protected String keyStoreType ="JKS";
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = "JKS";
protected String trustStorePassword ;
protected String certAlias ;

public void init() {
  keyStoreFile = (String)getOption("keyStoreFile");
  if(( keyStoreFile== null) )
    System.err.println("Please keyStoreFile configured for the Handler!");
  trustStoreFile = (String)getOption("trustStoreFile");
  if(( trustStoreFile== null) )
  System.err.println("Please trustStoreFile configured for the Handler!");
  keyStorePassword = (String)getOption("keyStorePassword");
  if(( keyStorePassword== null) )
  System.err.println("Please keyStorePassword configured for the Handler!");
  keyAlias = (String)getOption("keyAlias");
  if(( keyAlias== null) )
  System.err.println("Please keyAlias configured for the Handler!");
  keyEntryPassword = (String)getOption("keyEntryPassword");
  if(( keyEntryPassword== null) )
  System.err.println("Please keyEntryPassword configured for the Handler!");
  trustStorePassword = (String)getOption("trustStorePassword");
  if(( trustStorePassword== null) )
  System.err.println("Please trustStorePassword configured for the Handler!");
  certAlias = (String)getOption("certAlias");
  if ((certAlias==null))
    System.err.println("Please certAlias configured for the Handler!");
  if ((getOption("keyStoreType")) != null)
    keyStoreType = (String)getOption("keyStoreType");
  if ((getOption("trustStoreType")) != null)
    trustStoreType = (String)getOption("trustStoreType");
  }
public void invoke(MessageContext messageContext) throws AxisFault {
  //do nothing now!
}
public void onFault(MessageContext msgContext) {
  System.out.println("處理錯(cuò)誤,,這里忽略!");
    }
}
  
2,、寫客戶端的配置代碼client-config.wsdd,如下:
  <?xml version="1.0" encoding="UTF-8"?>
  <deployment name="defaultClientConfig"
    xmlns="http://xml./axis/wsdd/"
    xmlns:java="" target="_blank">http://xml./axis/wsdd/providers/java">
  <transport name="http"
    pivot="java:org.apache.axis.transport.http.HTTPSender"/>
  <transport name="local"
    pivot="java:org.apache.axis.transport.local.LocalSender"/>
  <transport name="java"
    pivot="java:org.apache.axis.transport.java.JavaSender"/>

<globalConfiguration>
<requestFlow>
  <handler type="java:com.ronghao.WSAxis.WSClientRequestHandler">
  <parameter name="keyStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.keystore"/>
  <parameter name="keyEntryPassword" value="changeit"/>
  <parameter name="certAlias" value="serverkey"/>
  <parameter name="trustStorePassword" value="changeit"/>
  <parameter name="trustStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.truststore"/>
  <parameter name="keyAlias" value="Client"/>
  <parameter name="keyStorePassword" value="changeit"/>
  </handler>
</requestFlow>
<responseFlow>
  <handler type="java:com.ronghao.WSAxis.WSClientResponseHandler">
  <parameter name="keyStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.keystore"/>
  <parameter name="keyEntryPassword" value="changeit"/>
  <parameter name="certAlias" value="serverkey"/>
  <parameter name="trustStorePassword" value="changeit"/>
  <parameter name="trustStoreFile" value="D:\Tomcat5.5\webapps\axis\WEB-INF\client.truststore"/>
  <parameter name="keyAlias" value="Client"/>
  <parameter name="keyStorePassword" value="changeit"/>
  </handler>
</responseFlow>
</globalConfiguration>
</deployment>
同樣不再解釋,,不明白可以參考我的上一篇文章

3、修改OrderClient.class
  在OrderClient.class中加入了如下代碼
  EngineConfiguration conf =
      new FileProvider("F:\\Tomcat\\webapps\\axis\\WEB-INF\\client-config.wsdd");//位置
  Service service = new Service(conf);
  當(dāng)然記得導(dǎo)入
  import org.apache.axis.EngineConfiguration;
  import org.apache.axis.configuration.FileProvider;
  
運(yùn)行一下,,返回"ronghao",,靠,搞定,!
注意:這次我把OrderClient.class的調(diào)用放到了一個(gè)JSP文件中而不是jbuilder中,,因?yàn)橛衏lient-config.wsdd,所以你必須有完整的WEB程序發(fā)布到TOMCAT中,,否則會(huì)報(bào)找不到
相應(yīng)文件,。 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多