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

打開APP
userphoto
未登錄

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

開通VIP
J2EE Web服務(wù)開發(fā)系列之六: 使用Handler來增強Web服務(wù)的功能

Handler的基本概念


J2EE Web 服務(wù)中的Handler技術(shù)特點非常像Servlet技術(shù)中的Filter。我們知道,在Servlet中,當一個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消息進行加密。當客戶端發(fā)送SOAP消⑹?,客户墩f腍andler把請求消息中的某些敏感的信息(如信用卡密碼)進行加密,然后把加密后的SOAP消息傳輸?shù)椒?wù)端;服務(wù)端的SOAP消息Handler截取客戶端的請求,把請求的SOAP 消息進行解密,然后把解密后的SOAP消息派發(fā)到目標的Web服務(wù)端點。

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




圖1 SOAP消息的傳遞順序

在圖中,軸心點(pivot point)是Apache與提供程序功能相當?shù)牟糠?,通過它來和目標的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ā)之前,我們先來看一下目標Web服務(wù)的端點實現(xiàn)類的代碼,如例程3所示。


例程3 目標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    {       //每當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的目的是對用戶認證,只有認證的用戶才能訪問目標服務(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 hellkingchen chen

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

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




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

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


例程6 在客戶端設(shè)置用戶名和密碼
http://127.0.0.1:808String 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è)置操作的名稱。            //由于需要認證,故需要設(shè)置調(diào)用的用戶名和密碼。            call.getMessageContext().setUsername("chen");            call.getMessageContext().setPassword("chen");          



回頁首


使用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)的用戶才能訪問目標服務(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),不能訪問目標服務(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ā)到目標服務(wù)。

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


例程8 要發(fā)送的訂單SOAP消息
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">    <soap-env:Header/>    <soapenv:Body>   <ns1:orderProduct soapenv:encodingStyle="http://schemas.xmlsoap.org/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之類的方法進行加密。加密之后的信息結(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="http://www.w3.org/2000/11/temp-xmlenc">    <ns3:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>    <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","","http://www.w3.org/2000/11/temp-xmlenc")); ele.addChildElement("DigestMethod").addAttribute(envelope.createName("Algorithm"),"http://www.w3.org/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));//對加密的信息編碼

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

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


例程11 服務(wù)端解密Handler
package com.hellking.webservice;import…//此handler的目的是把加密的SOAP消息解密成目標服務(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","http://www.w3.org/2000/11/temp-xmlenc"));    if(it3.hasNext())    value=((SOAPElement)it3.next()).getValue();//獲得加密的值       }       //把加密的SOAPMessage解密成目標服務(wù)可以調(diào)用的SOAP消息。    SOAPMessage   msg2=convertMessage(msg,this.decrypte(value));    msgContext.setMessage(msg2);              }      catch(Exception e)      {       e.printStackTrace();      }       }  //這個方法是把加密的數(shù)據(jù)進行解密,返回明文。 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的操作是相反的過程。



回頁首


總結(jié)


通過以上的討論,相信大家已經(jīng)掌握了Handler的基本使用技巧??梢钥闯觯ㄟ^使用Handler,可以給Web服務(wù)提供一些額外的功能。在實際的開發(fā)中,我們可以開發(fā)出一些通用的Handler,然后通過不同的搭配方式把它們部署到不同的Web服務(wù)中。

另外,在XML & Web services專區(qū)還有一篇關(guān)于使用Handler來為Web服務(wù)提供緩存功能的文章,您可以參考它, 《用高速緩存加速您的 Web 服務(wù)》

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
AXIS完全總結(jié)
Java - Webservice調(diào)用方式詳解
AXIS學習筆記(五)(?在AXIS服務(wù)間傳遞JavaBean及其安全...
九、WebService中文件傳輸
soap 頭部處理 mustunderstand
Java調(diào)用.NET webservice方法的幾種方式
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服