国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
AXIS完全總結(jié)

目錄

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

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

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

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

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

                          

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

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

一、軟件環(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下需要加入三個包 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)入

三、實驗一下

  在%AXIS_HOME%\webapps下找到axis文件夾,將其整個拷貝到%TOMCAT_HOME%\webapps下,啟動

Tomcat,打開瀏覽器訪問http://localhost:8080/axis/,出現(xiàn)以下頁面說明你配置成功了。很簡單吧:)


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

  第一個程序簡單的返回HELLO WORLD!

HelloWorld.java

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

}

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

將HelloWorld.java拷貝到%TOMCAT_HOME%\webapps\axis下,然后將其改名為HelloWorld.jws,這樣AXIS就自然將其發(fā)布了。現(xià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)建一個Service實例,注意是必須的!
    Call   call   = (Call) service.createCall();//創(chuàng)建Call實例,也是必須的!

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

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

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

                System.out.println( res );
  }
}

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

可以看到在AXIS里發(fā)布服務(wù)其實是一件很容易的事,這是因為這個服務(wù)很簡單的原因:)下面我們介紹第二種發(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="
  <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

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

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

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/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>

同樣用客戶端程序訪問一下:(注意和上邊的差別!?。?/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 );
  }
}

好了,相信你對AXIS已有了大致的了解。接下來將會涉及到傳參數(shù)、JAVABEAN對象,及AXIS的安全問題,下次再說吧:)也歡迎和我,一個快樂的JAVA程序員,聯(lián)系:)ronghao100@hotmail.com 

第三種方式:

 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.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

 <service provider="java:RPC">

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

  <parameter value="*"/>

 </service>

</deployment>

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

  編輯一個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í)行這個批處理文件,這時候,如果提示成功的話,訪問http://localhost:8080/test/services 就會顯示服務(wù)列表。

  4、生成客戶端client stub文件

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

  編寫一個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í)行這個批處理文件就可以生成client stub.

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

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

  下面是一段junit測試客戶端代碼。

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來增強Web服務(wù)的功能

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

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

下面我們來看一個典型的SOAP消息Handler處理順序: 
某個在線支付服務(wù)需要防止非授權(quán)的用戶訪問或者撰改服務(wù)端和客戶端傳輸?shù)男畔?,從而使用消息摘要(Message Digest)的方法對請求和響應(yīng)的SOAP消息進行加密。當(dāng)客戶端發(fā)送SOAP消⑹保?突Ф說?andler把請求消息中的某些敏感的信息(如信用卡密碼)進行加密,然后把加密后的SOAP消息傳輸?shù)椒?wù)端;服務(wù)端的SOAP消息Handler截取客戶端的請求,把請求的SOAP 消息進行解密,然后把解密后的SOAP消息派發(fā)到目標(biāo)的Web服務(wù)端點。 

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


圖1 SOAP消息的傳遞順序


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

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

在axis環(huán)境下,SOAP消息Handler必須實現(xiàn)org.apache.axis.Handler接口(在JAX-RPC 1.0規(guī)范中,SOAP消息Handler必須實現(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;
  …
}

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

例程2 BasicHandler的部分代碼


public abstract class BasicHandler implements Handler {
  protected static Log log =
    LogFactory.getLog(BasicHandler.class.getName());
  protected Hashtable options;
  protected String name;
  //這個方法必須在Handler中實現(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實現(xiàn)類必須實現(xiàn)的方法,它通過MessageContext來獲得請求或者響應(yīng)的SOAPMessage對象,然后對SOAPMessage進行處理。 

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

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


package com.hellking.webservice;
public class HandleredService 
{
//一個簡單的Web服務(wù)
public String publicMethod(String name)
{
return "Hello!"+name;
}
}
//另一個Web服務(wù)端點:
package com.hellking.webservice;
public class OrderService 
{
    //web服務(wù)方法:獲得客戶端的訂單信息,并且對訂單信息進行對應(yīng)的處理,
通常情況是把訂單的信息寫入數(shù)據(jù)庫,然后可客戶端返回確認信息。
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ā)送來的信息:");
System.out.println(orderInfo); 
return orderInfo;

}

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

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

Handler為系統(tǒng)做日志是一種比較常見而且簡單的使用方式。和Servlet中的Filter一樣,我們可以使用Handler來把用戶的訪問寫入系統(tǒng)日志。下面我們來看日志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,每一個handler都必須實現(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);
    }
  }
}

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

下面部署這個前面開發(fā)的Web服務(wù)對像,然后為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"/>
  …<!--在這里可以指定多個Handler-->
</requestFlow>
</service>


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

注意:這個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對用戶的訪問認證

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

對用戶認證的Handler代碼如下:

例程5 認證的Handler


package com.hellking.webservice;
import….

//此handler的目的是對用戶認證,只有認證的用戶才能訪問目標(biāo)服務(wù)。
public class AuthenticationHandler extends BasicHandler
{
/**invoke,每一個handler都必須實現(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();
      
      //對用戶進行認證,如果authUser==null,表示沒有通過認證,
拋出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);
        //用戶通過認證,把用戶的設(shè)置成認證了的用戶。
        msgContext.setProperty("authenticatedUser", authUser);
    } 
  }
}

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

部署這個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

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

圖2 訪問web服務(wù)時的驗證 

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

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


使用Handler對用戶的訪問授權(quán)

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

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


package com.hellking.webservice;

import…

//此handler的目的是對認證的用戶授權(quán),只有授權(quán)的用戶才能訪問目標(biāo)服務(wù)。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一個handler都必須實現(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;//訪問授權(quán)通過。
        }
    }
    //沒有通過授權(quá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)將匹配允許訪問Web服務(wù)的用戶,如果匹配成功,那么授權(quán)通過,如果沒有授權(quán)成功,那么拋出Server.Unauthorized異常。 

使用Handler對SOAP消息進行加密、解密

由于SOAP消息在HTTP協(xié)議中傳輸,而HTTP協(xié)議的安全度是比較低的,怎么保證信息安全到達對方而不泄漏或中途被撰改,將是Web服務(wù)必須解決的問題。圍繞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ù),要使信息安全到達對方,必須把它進行加密,然后在對方收到信息后解密。為了提供開發(fā)的方便,可以使用Handler技術(shù),在客戶端發(fā)送信息前,使用客戶端的Handler對SOAP消息中的關(guān)鍵信息進行加密;在服務(wù)端接收到消息后,有相應(yīng)的Handler把消息進行解密,然后才把SOAP消息派發(fā)到目標(biāo)服務(wù)。 

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

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

<soap-env:Envelope xmlns:soap-env="
  <soap-env:Header/>
  <soapenv:Body>
  <ns1:orderProduct soapenv:encodingStyle="
  </multiRef>
</soapenv:Body>
  </soap-env:Envelope>

    


上面的黑體字是傳輸?shù)拿舾行畔ⅲ市枰用?。我們可以使用Message Digest之類的方法進行加密。加密之后的信息結(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="

  <ns3:DigestMethod Algorithm="
  <ns3:DigestValue>rO0ABXQAkyA8Y2FyZ…….
</ns3:DigestValue>
  </ns3:EncryptedData>
</multiRef>
</soapenv:Body>
</soapenv:Envelope>


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


圖3 SOAP消息的加密和解密 

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

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

例程10 對SOAP消息的敏感部分加密


      SOAPElement ele= soapBodyElement.addChildElement(envelope.createName
("EncryptedData","","

  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));//對加密的信息編碼

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

服務(wù)端接收到加密的信息后,解密的Handler會把對應(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,每一個handler都必須實現(xiàn)的方法。
*/
public void invoke(MessageContext msgContext)throws AxisFault
{
try
{   
  //從messageContext例取得SOAPMessage對象。
  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的最后一個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","
  md.update(data.getBytes());
}
      …
return data;
}
  //把解密后的信息重新組裝成服務(wù)端能夠使用的SOAP消息。
public SOAPMessage convertMessage(SOAPMessage msg,String data)
{   
  ….
}
}     

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

總結(jié)

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

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

2、在目錄%TOMCAT_HOME%\webapps\axis\WEB-INF下打開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="
    <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中你會找到這段代碼
  <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、啟動Tomcat,打開
http://localhost:8080/axis/SOAPMonitor,你就會看到Applet界面,在
  jbuilder2005中運行我們上次寫的客戶端程序 TestClient.java。OK!你會在Applet界面看
  見客戶端與服務(wù)器端互發(fā)的XML內(nèi)容,注意這里是明文!
  
二、使用axis的Handler進行訪問控制(對安全要求不高時推薦)
  axis為Web服務(wù)的訪問控制提供了相關(guān)的配置描述符,并且提供了一個訪問控制的簡單 Handler。默認情況下,你只要在配置描述符中添加用戶,然后在Web服務(wù)器的部署描述符中自動允許的角色即可。

1、在axis的配置文件users.lst(位于WEB-INF目錄下)中添加一個用戶,如"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>
在這個部署描述符中,指定HelloWorld服務(wù)只能被ronghao訪問
  
3、修改客戶端程序 TestClient.java,增加訪問用戶名、密碼(新加的部分已標(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,能夠順利訪問Web服務(wù);如果修改用戶名或者密碼,那么就不能訪問 。同樣,
你在http://localhost:8080/axis/SOAPMonitor中看到的請求和響應(yīng)的XML是明文!

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

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

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

3)同理生成客戶端的密匙庫client.keystore和服務(wù)器端的信任庫server.truststore.方便起見給出.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)在我們就有了四個文件:server.keystore,server.truststore,client.keystore,client.truststore

2、更改Tomcat的配置文件(server.xml),增加以下部署描述符:(其實里面有,只是被注釋掉了)
    <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、最后使用命令來執(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ī)范對信息進行加密與身份認證
  我們打算用Handler結(jié)合WSSecurity實現(xiàn)Web服務(wù)安全(Handler的有關(guān)內(nèi)容請參閱AXIS學(xué)習(xí)筆記(二))
  設(shè)想流程:用WSClientRequestHandler.java位于客戶端對客戶端發(fā)出的XML文檔進行加密
          WSServerRequestHandler.java位于服務(wù)器端對客戶端發(fā)出的加密后的XML文檔進行解密
          WSServerResponseHandler.java位于服務(wù)器端對服務(wù)器端返回的XML文檔進行加密
          WSClientResponseHandler.java位于客戶端對服務(wù)器端返回的XML文檔進行解密
          
1、使用ISNetworks安全提供者,ISNetworks實現(xiàn)了RSA加密、解密算法。
  當(dāng)然,你也可以使用其它的安全提供者,并且可以使用不同的加密算法。
  ISNetworks相關(guān)包ISNetworksProvider.jar??截惖?TOMCAT_HOME%   \webapps\axis\WEB-INF\lib
  
2、Trust Services Integration Kit提供了一個WS-Security實現(xiàn)。你可以從http://www.xmltrustcenter.org獲得相關(guān)庫文件,分別是ws-security.jar和tsik.jar。ws-security.jar中包含一個WSSecurity類,我們使用它來對XML進行數(shù)字簽名和驗證,加密與解密。同樣拷貝到%TOMCAT_HOME%\webapps\axis\WEB-INF\lib

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

5、具體分析(在此強烈建議看一下tsik.jar的API)
  WSHelper.java 
  public class WSHelper {
    static String PROVIDER="ISNetworks";//JSSE安全提供者。
//添加JSSE安全提供者,你也可以使用其它安全提供者。只要支持DESede算法。這是程序里動態(tài)加載還可以在JDK中靜態(tài)加載
    static
    {
      java.security.Security.addProvider(new com.isnetworks.provider.jce.ISNetworksProvider());
  }
  /**
  *對XML文檔進行數(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);//簽名。


    }
  /**
  *對XML文檔進行身份驗證。
  */
    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;
    }
  /**
  *對XML文檔進行加密。必須有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();
    }
    }
  /**
  *對文檔進行解密。
  */
    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";//默認
protected String keyStorePassword ;
protected String keyAlias ;
protected String keyEntryPassword ;
protected String trustStoreFile ;
protected String trustStoreType = "JKS";//默認
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 {//在這個方法里對XML文檔進行處理
  //do nothing now!
}
public void onFault(MessageContext msgContext) {
  System.out.println("處理錯誤,這里忽略!");
    }
}

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)時發(fā)生以下錯誤: " + 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);//驗證
        WSHelper.removeWSSElements(doc);
        soapMessage = MessageConverter.convertDocumentToSOAPMessage(doc);
        messageContext.setMessage(soapMessage);
  } catch (Exception e){
        e.printStackTrace();
        System.err.println("在處理響應(yīng)時發(fā)生以下錯誤: " + e);
                }

    }
}   
  
  WSServerHandler.java 
  public class WSServerHandler 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 invoke(MessageContext messageContext) throws AxisFault {
  //do nothing now!
}
public void onFault(MessageContext msgContext) {
  System.out.println("處理錯誤,這里忽略!");
    }
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);//驗證
        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)時發(fā)生以下錯誤: " + 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)時發(fā)生以下錯誤: " + 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();
    }
  }


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

一、服務(wù)器端
1、CLASS類兩個Order.class,OrderTest.class,位于%TOMCAT_HOME%\webapps\axis\WEB-INF\classes下
  這兩個類都直接給出源碼,不再說明
  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類的名字
  其他是固定的。
  
二、客戶端
  客戶端類文件一個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();
    //注冊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!運行一下,就可以看到返回了"ronghao"。

和上一篇文章一樣,我們不容許在網(wǎng)絡(luò)中傳遞XML是明文,于是需要加密和驗證。這里我們繼續(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>首先在這里要說一下,客戶端代碼編寫困擾了我很長一段時間(整整一天),因為它并不象我想象的那么簡單,當(dāng)然解決起來還是挺簡單的:)問題的解決經(jīng)歷了三個階段

第一階段:
  在這個階段我想當(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
  這個方法也是我在上一文章里介紹的,結(jié)果拋出以下異常:
  faultString: org.xml.sax.SAXException: Deserializing parameter
  'newProfileReturn': could not find deserializer for type
  {urn:BeanService Order}SerializableProfile
  也就是說不能正常解析XML文件,于是理所當(dāng)然的郁悶了,覺得代碼中肯定漏設(shè)了CALL的一個屬性,于是查看AXIS的源代碼,沒有結(jié)果!轉(zhuǎn)機出現(xiàn)在下面一行代碼,在不斷的拋出異常中我修改了代碼
  將call.setClientHandlers(handler,handlee);改為
  call.setClientHandlers(null,null);
  結(jié)果程序還是拋出同樣的異常,于是意識到這可能是AXIS的一個BUG,為證明這一點,我將下面的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!得到這個結(jié)論后去了apache AXIS主頁,在問題列表中見到了完全一樣問題的提交,但沒有解答(暈?。?br>  最后得到了結(jié)論:call的setClientHandlers()方法只有當(dāng)call處理簡單的數(shù)據(jù)類型,如String,int等等才能正常使用!
  (當(dāng)然,如果你對這個問題有不同的見解,歡迎和我聯(lián)系。或許我錯了,但程序不運行是真的:))
  
第二階段:
  開始在google上找問題的解決方法,這也是我的習(xí)慣:)。找了一個類似問題的討論,地址如下:
  http://marc.theaimsgroup.com/?l=axis-user&m=111259980822735&w=2
  他們的解決方法是Handler繼承于javax.xml.rpc.handler.Handler,然后在程序里動態(tài)注冊而在我的ws-axis.jar里Handler繼承于org.apache.axis.handlers.BasicHandler。當(dāng)然,
  javax.xml.rpc.handler.Handler是org.apache.axis.handlers.BasicHandler的老爸,但在程序里老爸和兒子之間卻不能很好的兼容,這也許就是所謂的代溝??無奈中重新寫了Handler,但在運行中卻拋出異常,提示message在被invoke的時候已被更改。我靠,Handler的作用就是來更改message的啊!這是什么世道!
  我知道很多程序采用的就是這種方法,但我好象怎么修改都拋出上述異常。
  
第三階段
  既然在程序里動態(tài)注冊Handler行不通,于是決定寫個單獨的配置文件來注冊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("處理錯誤,這里忽略!");
    }
}
  
2、寫客戶端的配置代碼client-config.wsdd,如下:
  <?xml version="1.0" encoding="UTF-8"?>
  <deployment name="defaultClientConfig"
    xmlns="
  <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;
  
運行一下,返回"ronghao",靠,搞定!
注意:這次我把OrderClient.class的調(diào)用放到了一個JSP文件中而不是jbuilder中,因為有client-config.wsdd,所以你必須有完整的WEB程序發(fā)布到TOMCAT中,否則會報找不到
相應(yīng)文件。 

打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
AXIS學(xué)習(xí)筆記(三)(建立安全的AXIS服務(wù)上)
實現(xiàn)安全的AXIS Web服務(wù),第1部分
利用AXIS開發(fā)Webservice(五) —— 如何傳遞文件
AXIS實現(xiàn)Web服務(wù)深入篇
J2ME與WebService-KSOAP的羅曼史
單點登錄學(xué)習(xí)(1)CAS服務(wù)器端配置編程
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服