- 浏览: 163025 次
- 性别:
- 来自: 合肥
文章分类
最新评论
-
panamera:
MQ服务器没有启动,消息生产者一直等待,不会报连接异常,这个问 ...
Spring3 JmsTemplate与MQ的集成 -
lanbo316:
[/size][align=left][size=xx-lar ...
Mybatis分页-利用Mybatis Generator插件生成基于数据库方言的分页语句,统计记录总数 -
fatalfeel:
Irrlicht 3d Engine is full open ...
Android世界的15款开源的游戏开发引擎 -
yakecjh:
哥们能份这个示例的代码给我么,我是北京科瑞明的,我现在正要做M ...
Spring3 JmsTemplate与MQ的集成 -
ma860709:
除了配置~能列一下配置的属性的意思还有代码的实现吗?
Spring3 JmsTemplate与MQ的集成
1,AXIS提供的工具
Apache Axis提供了WSDL2Java和Java2WSDL两个开发工具。
WSDL2Java利用已知的WSDL文件生成服务端和客户端代码。该WSDL文件可以是由合作伙伴提供的,也可以是利用Java2WSDL生成的。Java2WSDL根据已有的Java类文件生成WSDL文件,Java类文件可以是接口类文件,并不需要实现细节。
此外Axis还提供了SoapMonitorApplet和TCPMon工具,可用于监测Web服务。
使用Handler来增强Web服务的功能
Handler的基本概念
J2EE Web 服务中的Handler技术特点非常像Servlet技术中的Filter。我们知道,在Servlet中,当一个HTTP到达服务端时,往往要经过多个Filter对请求进行过滤,然后才到达提供服务的Servlet,这些Filter的功能往往是对请求进行统一编码,对用户进行认证,把用户的访问写入系统日志等。相应的,Web服务中的Handler通常也提供以下的功能:
对客户端进行认证、授权;
把用户的访问写入系统日志;
对请求的SOAP消息进行加密,解密;
为Web Services对象做缓存。
SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。在JAX-RPC技术中,SOAP消息Handler可以部署在服务端,也可以在客户端使用。
下面我们来看一个典型的SOAP消息Handler处理顺序:
某个在线支付服务需要防止非授权的用户访问或者撰改服务端和客户端传输的信息,从而使用消息摘要(Message Digest)的方法对请求和响应的SOAP消息进行加密。当客户端发送SOAP消息时,Handler把请求消息中的某些敏感的信息(如信用卡密码)进行加密,然后把加密后的SOAP消息传输到服务端;服务端的SOAP消息Handler截取客户端的请求,把请求的SOAP 消息进行解密,然后把解密后的SOAP消息派发到目标的Web服务端点。
Apache axis是我们当前开发Web服务的较好的选择,使用axisWeb服务开发工具,可以使用Handler来对服务端的请求和响应进行处理。典型的情况下,轴心点(pivot point)是Apache与提供程序功能相当的部分,通过它来和目标的Web服务进行交互,它通常称为Provider。axis中常用的Provider有Java:RPC,java:MSG,java:EJB。一个Web服务可以部署一个或者多个Handler。
Apache axis中的Handler体系结构和JAX-RPC 1.0(JSR101)中的体系结构稍有不同,需要声明的是,本文的代码在axis中开发,故需要在axis环境下运行。
在axis环境下,SOAP消息Handler必须实现org.apache.axis.Handler接口(在JAX-RPC 1.0规范中,SOAP消息Handler必须实现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;
…
}
为了提供开发的方便,在编写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中实现。
public abstract void invoke(MessageContext msgContext) throws AxisFault;
public void setOption(String name, Object value) {
if ( options == null ) initHashtable();
options.put( name, value );
}
…
}
BasicHandler中的public abstract void invoke(MessageContext msgContext) 方法是Handler实现类必须实现的方法,它通过MessageContext来获得请求或者响应的SOAPMessage对象,然后对SOAPMessage进行处理。
在介绍Handler的开发之前,我们先来看一下目标Web服务的端点实现类的代码,如例程3所示。
例程3 目标Web服务的端点实现类
package com.hellking.webservice;
public class HandleredService
{
//一个简单的Web服务
public String publicMethod(String name)
{
return "Hello!"+name;
}
}
//另一个Web服务端点:
package com.hellking.webservice;
public class OrderService
{
//web服务方法:获得客户端的订单信息,并且对订单信息进行对应的处理,
通常情况是把订单的信息写入数据库,然后向客户端返回确认信息。
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("这里是客户端发送来的信息:");
System.out.println(orderInfo);
return orderInfo;
}
}
下面我们分不同情况讨论Handler的使用实例。
使用Handler为系统做日志
Handler为系统做日志是一种比较常见而且简单的使用方式。和Servlet中的Filter一样,我们可以使用Handler来把用户的访问写入系统日志。下面我们来看日志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都必须实现的方法。
*/
public void invoke(MessageContext msgContext) throws AxisFault
{
//每当web服务被调用,都记录到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 服务 " +
msgContext.getTargetService() +
" 被调用,现在已经共调用了 " + counter + " 次.";
handler.setOption("accesses", counter);
writer.println(result);
writer.close();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
前面我们说过,Handler实现类必须实现invoke方法,invoke方法是Handler处理其业务的入口点。LogHandler的主要功能是把客户端访问的Web服务的名称和访问时间、访问的次数记录到一个日志文件中。
下面部署这个前面开发的Web服务对像,然后为Web服务指定Handler。编辑Axis_Home/WEB-INF/ server-config.wsdd文件,在其中加入以下的内容:
<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需要根据具体情况改变。
在Sun Jul 06 22:42:03 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 1 次.
在Sun Jul 06 22:42:06 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 2 次.
在Sun Jul 06 22:42:13 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 3 次.
使用Handler对用户的访问认证
使用Handler为用户访问认证也是它的典型使用,通过它,可以减少在Web服务端代码中认证的麻烦,同时可以在部署描述符中灵活改变用户的访问权限。
对用户认证的Handler代码如下:
例程5 认证的Handler
package com.hellking.webservice;
import….
//此handler的目的是对用户认证,只有认证的用户才能访问目标服务。
public class AuthenticationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
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);
//用户通过认证,把用户的设置成认证了的用户。
msgContext.setProperty("authenticatedUser", authUser);
}
}
}
在AuthenticationHandler代码里,它从MessageContext中获得用户信息,然后进行认证,如果认证成功,那么就使用msgContext.setProperty("authenticatedUser", authUser)方法把用户设置成认证了的用户,如果认证不成功,那么就抛出Server.Unauthenticated异常。
部署这个Handler,同样,在server-config里加入以下的内容:
<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
将会提示输入用户名和密码。
访问web服务时的验证,如果客户端是应用程序,那么可以这样在客户端设置用户名和密码:
例程6 在客户端设置用户名和密码
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") );//设置操作的名称。
//由于需要认证,故需要设置调用的用户名和密码。
call.getMessageContext().setUsername("chen");
call.getMessageContext().setPassword("chen");
使用Handler对用户的访问授权
对于已经认证了的用户,有时在他们操作某个特定的服务时,还需要进行授权,只有授权的用户才能继续进行操作。我们看对用户进行授权的Handler的代码。
例程7 对用户进行授权的代码
package com.hellking.webservice;
import…
//此handler的目的是对认证的用户授权,只有授权的用户才能访问目标服务。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
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;//访问授权通过。
}
}
//没有通过授权,不能访问目标服务,抛出Server.Unauthorized异常。
throw new AxisFault("Server.Unauthorized",
Messages.getMessage("cantAuth02", userId, serviceName), null, null);
}
}
在service-config.wsdd文件中,我们为Web服务指定了以下的用户:
<parameter name="allowedRoles" value="chen,hellking"/>
provider.userMatches(user, thisRole)将匹配允许访问Web服务的用户,如果匹配成功,那么授权通过,如果没有授权成功,那么抛出Server.Unauthorized异常。
使用Handler对SOAP消息进行加密、解密
由于SOAP消息在HTTP协议中传输,而HTTP协议的安全度是比较低的,怎么保证信息安全到达对方而不泄漏或中途被撰改,将是Web服务必须解决的问题。围绕Web服务的安全,有很多相关的技术,比如WS-Security,WS-Trace等,另外,还有以下相关技术:
XML Digital Signature(XML数字签名)
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
不管使用什么技术,要使信息安全到达对方,必须把它进行加密,然后在对方收到信息后解密。为了提供开发的方便,可以使用Handler技术,在客户端发送信息前,使用客户端的Handler对SOAP消息中的关键信息进行加密;在服务端接收到消息后,有相应的Handler把消息进行解密,然后才把SOAP消息派发到目标服务。
下面我们来看一个具体的例子。加入使用SOAP消息发送订单的信息,订单的信息如下:
例程8 要发送的订单SOAP消息
<soap-env:Envelope xmlns:soap-env="" target="_blank">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>
上面的黑体字是传输的敏感信息,故需要加密。我们可以使用Message Digest之类的方法进行加密。加密之后的信息结构如下:
例程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.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>
使用Handler对SOAP消息进行加密、解密后,SOAP消息在传递过程中结构会改变。
可以看出,通过使用加密、解密的Handler,可以确保消息的安全传递。进一步说,如果把这种Handler做成通用的组件,那么就可以灵活地部署到不同的服务端和客户端。
客户端的Handler的功能是把SOAP消息使用一定的规则加密,假如使用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));//对加密的信息编码
在客户端发送出SOAP消息时,客户端的Handler拦截发送的SOAP消息,然后对它们进行加密,最后把加密的信息传送到服务端。
服务端接收到加密的信息后,解密的Handler会把对应的加密信息解密。服务端Handler代码如下:
package com.hellking.webservice;
import…
//此handler的目的是把加密的SOAP消息解密成目标服务可以使用的SOAP消息。
public class MessageDigestHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
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解密成目标服务可以调用的SOAP消息。
SOAPMessage msg2=convertMessage(msg,this.decrypte(value));
msgContext.setMessage(msg2);
}
catch(Exception e)
{
e.printStackTrace();
}
}
//这个方法是把加密的数据进行解密,返回明文。
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;
}
//把解密后的信息重新组装成服务端能够使用的SOAP消息。
public SOAPMessage convertMessage(SOAPMessage msg,String data)
{
….
}
}
可以看出,服务端解密的Handler和客户端加密的Handler的操作是相反的过程。
总结
通过以上的讨论,相信大家已经掌握了Handler的基本使用技巧。可以看出,通过使用Handler,可以给Web服务提供一些额外的功能。在实际的开发中,我们可以开发出一些通用的Handler,然后通过不同的搭配方式把它们部署到不同的Web服务中。
Apache Axis提供了WSDL2Java和Java2WSDL两个开发工具。
WSDL2Java利用已知的WSDL文件生成服务端和客户端代码。该WSDL文件可以是由合作伙伴提供的,也可以是利用Java2WSDL生成的。Java2WSDL根据已有的Java类文件生成WSDL文件,Java类文件可以是接口类文件,并不需要实现细节。
此外Axis还提供了SoapMonitorApplet和TCPMon工具,可用于监测Web服务。
使用Handler来增强Web服务的功能
Handler的基本概念
J2EE Web 服务中的Handler技术特点非常像Servlet技术中的Filter。我们知道,在Servlet中,当一个HTTP到达服务端时,往往要经过多个Filter对请求进行过滤,然后才到达提供服务的Servlet,这些Filter的功能往往是对请求进行统一编码,对用户进行认证,把用户的访问写入系统日志等。相应的,Web服务中的Handler通常也提供以下的功能:
对客户端进行认证、授权;
把用户的访问写入系统日志;
对请求的SOAP消息进行加密,解密;
为Web Services对象做缓存。
SOAP消息Handler能够访问代表RPC请求或者响应的SOAP消息。在JAX-RPC技术中,SOAP消息Handler可以部署在服务端,也可以在客户端使用。
下面我们来看一个典型的SOAP消息Handler处理顺序:
某个在线支付服务需要防止非授权的用户访问或者撰改服务端和客户端传输的信息,从而使用消息摘要(Message Digest)的方法对请求和响应的SOAP消息进行加密。当客户端发送SOAP消息时,Handler把请求消息中的某些敏感的信息(如信用卡密码)进行加密,然后把加密后的SOAP消息传输到服务端;服务端的SOAP消息Handler截取客户端的请求,把请求的SOAP 消息进行解密,然后把解密后的SOAP消息派发到目标的Web服务端点。
Apache axis是我们当前开发Web服务的较好的选择,使用axisWeb服务开发工具,可以使用Handler来对服务端的请求和响应进行处理。典型的情况下,轴心点(pivot point)是Apache与提供程序功能相当的部分,通过它来和目标的Web服务进行交互,它通常称为Provider。axis中常用的Provider有Java:RPC,java:MSG,java:EJB。一个Web服务可以部署一个或者多个Handler。
Apache axis中的Handler体系结构和JAX-RPC 1.0(JSR101)中的体系结构稍有不同,需要声明的是,本文的代码在axis中开发,故需要在axis环境下运行。
在axis环境下,SOAP消息Handler必须实现org.apache.axis.Handler接口(在JAX-RPC 1.0规范中,SOAP消息Handler必须实现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;
…
}
为了提供开发的方便,在编写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中实现。
public abstract void invoke(MessageContext msgContext) throws AxisFault;
public void setOption(String name, Object value) {
if ( options == null ) initHashtable();
options.put( name, value );
}
…
}
BasicHandler中的public abstract void invoke(MessageContext msgContext) 方法是Handler实现类必须实现的方法,它通过MessageContext来获得请求或者响应的SOAPMessage对象,然后对SOAPMessage进行处理。
在介绍Handler的开发之前,我们先来看一下目标Web服务的端点实现类的代码,如例程3所示。
例程3 目标Web服务的端点实现类
package com.hellking.webservice;
public class HandleredService
{
//一个简单的Web服务
public String publicMethod(String name)
{
return "Hello!"+name;
}
}
//另一个Web服务端点:
package com.hellking.webservice;
public class OrderService
{
//web服务方法:获得客户端的订单信息,并且对订单信息进行对应的处理,
通常情况是把订单的信息写入数据库,然后向客户端返回确认信息。
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("这里是客户端发送来的信息:");
System.out.println(orderInfo);
return orderInfo;
}
}
下面我们分不同情况讨论Handler的使用实例。
使用Handler为系统做日志
Handler为系统做日志是一种比较常见而且简单的使用方式。和Servlet中的Filter一样,我们可以使用Handler来把用户的访问写入系统日志。下面我们来看日志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都必须实现的方法。
*/
public void invoke(MessageContext msgContext) throws AxisFault
{
//每当web服务被调用,都记录到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 服务 " +
msgContext.getTargetService() +
" 被调用,现在已经共调用了 " + counter + " 次.";
handler.setOption("accesses", counter);
writer.println(result);
writer.close();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
前面我们说过,Handler实现类必须实现invoke方法,invoke方法是Handler处理其业务的入口点。LogHandler的主要功能是把客户端访问的Web服务的名称和访问时间、访问的次数记录到一个日志文件中。
下面部署这个前面开发的Web服务对像,然后为Web服务指定Handler。编辑Axis_Home/WEB-INF/ server-config.wsdd文件,在其中加入以下的内容:
<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需要根据具体情况改变。
在Sun Jul 06 22:42:03 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 1 次.
在Sun Jul 06 22:42:06 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 2 次.
在Sun Jul 06 22:42:13 CST 2003: Web 服务 HandleredService 被调用,现在已经共调用了 3 次.
使用Handler对用户的访问认证
使用Handler为用户访问认证也是它的典型使用,通过它,可以减少在Web服务端代码中认证的麻烦,同时可以在部署描述符中灵活改变用户的访问权限。
对用户认证的Handler代码如下:
例程5 认证的Handler
package com.hellking.webservice;
import….
//此handler的目的是对用户认证,只有认证的用户才能访问目标服务。
public class AuthenticationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
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);
//用户通过认证,把用户的设置成认证了的用户。
msgContext.setProperty("authenticatedUser", authUser);
}
}
}
在AuthenticationHandler代码里,它从MessageContext中获得用户信息,然后进行认证,如果认证成功,那么就使用msgContext.setProperty("authenticatedUser", authUser)方法把用户设置成认证了的用户,如果认证不成功,那么就抛出Server.Unauthenticated异常。
部署这个Handler,同样,在server-config里加入以下的内容:
<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
将会提示输入用户名和密码。
访问web服务时的验证,如果客户端是应用程序,那么可以这样在客户端设置用户名和密码:
例程6 在客户端设置用户名和密码
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") );//设置操作的名称。
//由于需要认证,故需要设置调用的用户名和密码。
call.getMessageContext().setUsername("chen");
call.getMessageContext().setPassword("chen");
使用Handler对用户的访问授权
对于已经认证了的用户,有时在他们操作某个特定的服务时,还需要进行授权,只有授权的用户才能继续进行操作。我们看对用户进行授权的Handler的代码。
例程7 对用户进行授权的代码
package com.hellking.webservice;
import…
//此handler的目的是对认证的用户授权,只有授权的用户才能访问目标服务。
public class AuthorizationHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
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;//访问授权通过。
}
}
//没有通过授权,不能访问目标服务,抛出Server.Unauthorized异常。
throw new AxisFault("Server.Unauthorized",
Messages.getMessage("cantAuth02", userId, serviceName), null, null);
}
}
在service-config.wsdd文件中,我们为Web服务指定了以下的用户:
<parameter name="allowedRoles" value="chen,hellking"/>
provider.userMatches(user, thisRole)将匹配允许访问Web服务的用户,如果匹配成功,那么授权通过,如果没有授权成功,那么抛出Server.Unauthorized异常。
使用Handler对SOAP消息进行加密、解密
由于SOAP消息在HTTP协议中传输,而HTTP协议的安全度是比较低的,怎么保证信息安全到达对方而不泄漏或中途被撰改,将是Web服务必须解决的问题。围绕Web服务的安全,有很多相关的技术,比如WS-Security,WS-Trace等,另外,还有以下相关技术:
XML Digital Signature(XML数字签名)
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
不管使用什么技术,要使信息安全到达对方,必须把它进行加密,然后在对方收到信息后解密。为了提供开发的方便,可以使用Handler技术,在客户端发送信息前,使用客户端的Handler对SOAP消息中的关键信息进行加密;在服务端接收到消息后,有相应的Handler把消息进行解密,然后才把SOAP消息派发到目标服务。
下面我们来看一个具体的例子。加入使用SOAP消息发送订单的信息,订单的信息如下:
例程8 要发送的订单SOAP消息
<soap-env:Envelope xmlns:soap-env="" target="_blank">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>
上面的黑体字是传输的敏感信息,故需要加密。我们可以使用Message Digest之类的方法进行加密。加密之后的信息结构如下:
例程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.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>
使用Handler对SOAP消息进行加密、解密后,SOAP消息在传递过程中结构会改变。
可以看出,通过使用加密、解密的Handler,可以确保消息的安全传递。进一步说,如果把这种Handler做成通用的组件,那么就可以灵活地部署到不同的服务端和客户端。
客户端的Handler的功能是把SOAP消息使用一定的规则加密,假如使用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));//对加密的信息编码
在客户端发送出SOAP消息时,客户端的Handler拦截发送的SOAP消息,然后对它们进行加密,最后把加密的信息传送到服务端。
服务端接收到加密的信息后,解密的Handler会把对应的加密信息解密。服务端Handler代码如下:
package com.hellking.webservice;
import…
//此handler的目的是把加密的SOAP消息解密成目标服务可以使用的SOAP消息。
public class MessageDigestHandler extends BasicHandler
{
/**invoke,每一个handler都必须实现的方法。
*/
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解密成目标服务可以调用的SOAP消息。
SOAPMessage msg2=convertMessage(msg,this.decrypte(value));
msgContext.setMessage(msg2);
}
catch(Exception e)
{
e.printStackTrace();
}
}
//这个方法是把加密的数据进行解密,返回明文。
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;
}
//把解密后的信息重新组装成服务端能够使用的SOAP消息。
public SOAPMessage convertMessage(SOAPMessage msg,String data)
{
….
}
}
可以看出,服务端解密的Handler和客户端加密的Handler的操作是相反的过程。
总结
通过以上的讨论,相信大家已经掌握了Handler的基本使用技巧。可以看出,通过使用Handler,可以给Web服务提供一些额外的功能。在实际的开发中,我们可以开发出一些通用的Handler,然后通过不同的搭配方式把它们部署到不同的Web服务中。
发表评论
-
使用TCPMonitor监控WebService SOAP消息
2010-08-04 16:49 2021使用Apache axis的TCPMonitor可以监控Web ... -
AXIS第五课:AXIS高级应用,在AXIS服务间传递JavaBean及其安全解决
2010-08-04 11:35 1023这是AXIS学习笔记的最后一篇。在前面我们讨论了最简单的Hel ... -
AXIS第四课:AXIS高级应用,建立安全的AXIS服务
2010-08-04 11:35 1338在前面的文章中,我们实现了最简单的AXIS服务。现在我们一起来 ... -
AXIS第二课:工程应用中的AXIS的发布方法Stub
2010-08-04 11:32 1446工程应用当中的web service的参数和通回值通常都是一个 ... -
AXIS第一课:最简单的发布AXIS的Web Service
2010-08-04 11:31 21771,简单介绍 本文并不 ...
相关推荐
3. **AXIS第三课:AXIS高级应用,使用Handler来增强Web服务的功能** Handler是Axis中一个强大的特性,允许开发者插入自定义逻辑在服务处理流程的各个阶段。你可以通过编写Handler来实现如认证、日志记录、消息转换...
Apache Axis 系统架构及Axis 设计基本原理 Apache Axis 是一个基于 Java 的 SOAP 服务器和客户端框架,... Axis 框架的设计原则是可扩展性、可重用性和高性能,它们使得 Axis 框架成为一个广泛应用的 Web 服务框架。
本文将详细介绍Axis2的API及其在Web服务开发中的应用,同时也会探讨Axis2的帮助文档如何协助开发者更好地理解和使用这个框架。 ### Axis2简介 Axis2是Apache Axis的第二代版本,它在第一代的基础上进行了许多改进和...
3. **发布Web服务**:使用wsdd文件发布Web服务是Axis的一个特性。wsdd(Web Service Deployment Descriptor)文件是XML格式,用于定义服务的元数据,包括服务的端点、操作、数据类型等。创建一个wsdd文件,例如`...
#### 三、AXIS高级应用,使用Handler来增强Web服务的功能 **知识点概述:** 本节介绍如何使用Handler来扩展Axis的Web服务功能,增强其灵活性和安全性。 **知识点详述:** 1. **Handler的定义** - Handler是在...
本篇文章将详细阐述如何使用Axis1.1发布Web服务,并通过一个简单的Eclipse工程实例来演示整个过程。 首先,我们需要了解Web服务的基本概念。Web服务是一种通过Internet进行通信的软件系统,它使用标准的XML格式传输...
Axis2是Apache Software Foundation(ASF)旗下的一个开源项目,它是第二代Axis项目,专注于提供一个高性能、灵活的Web服务栈。Axis2支持SOAP 1.1和1.2标准,并且可以部署在多种环境和平台上。 ##### 关键概念 - *...
通过理解并实践这些知识点,开发者可以高效地使用Axis和wsdd文件来部署和管理自己的Web服务,从而在分布式系统中实现灵活的数据交换和功能调用。记住,实践是检验理论的最好方式,所以动手试试看吧!
标题 "Axis Webservice Demo" 暗示了我们将探讨如何使用Apache Axis库创建和使用Web服务。Apache Axis是一个开源框架,专门用于构建基于SOAP(简单对象访问协议)的Web服务。这个Demo很可能是为了演示如何在Java环境...
4. **模块和服务组件**:学习如何编写自定义模块以扩展Axis2的功能,以及如何使用Service Archive(SAR)和Web Application Archive(WAR)文件打包服务。 5. **异常处理和安全性**:了解如何在Axis2中处理错误和...
Axis.jar作为Web服务客户端和服务器端的核心库,包含了处理SOAP消息、WSDL(Web服务描述语言)解析、类型映射和WS-I(Web服务互操作性)规范实现等关键功能。其设计目标是使开发人员能够轻松地创建和部署Web服务,...
7. **扩展性**:通过使用Handler链,Axis1.4允许开发者插入自定义逻辑,如身份验证、日志记录、数据转换等,增强了Web服务的灵活性和功能。 8. **错误处理和调试**:Axis1.4提供了详细的错误信息和日志记录,方便...
本文将详细介绍如何使用Apache Axis库来实现这一功能,并提供相关步骤和注意事项。 首先,理解HTTPS(超文本传输安全协议)是HTTP的安全版本,它通过SSL/TLS协议对数据进行加密,以确保数据在传输过程中的隐私和...
3. **使用Axis2作为Web服务引擎**:在Spring配置中,你需要指定Axis2作为Web服务的运行时环境,这通常涉及到添加相应的bean配置。 4. **服务发布**:Spring可以自动发现标记为Web服务的bean,并使用Axis2将其发布到...
Apache Axis 1.4 Final 是一个历史悠久且广泛使用的SOAP(Simple Object Access Protocol)Web服务框架,主要用于构建和部署Web服务。这个版本是Axis 1.x系列的一个稳定版本,发布于2009年,旨在提供可靠的SOAP通信...
**Xfire** 是一个游戏社区平台,它通过 Web 服务接口允许第三方应用与 Xfire 服务器通信,获取用户的游戏状态、好友列表等信息。Xfire 的 Web 服务接口可能包括: 1. **用户信息查询**:获取用户的在线状态、正在玩...
8. **扩展性**:Axis2 的设计允许开发者通过编写自定义模块、消息处理器和服务拦截器(Handler)来扩展其功能,满足各种复杂应用场景的需求。 9. **互操作性**:作为SOAP 1.1和1.2的实现,Axis2 具有良好的互操作性...
总结来说,"axis最新API"是一个强大的工具,为开发者提供了构建、部署和使用Web服务的全面支持。通过深入理解这个API,开发者能够更好地利用其功能,创建安全、高效的Web服务解决方案。记得利用`apiDocs`中的文档,...
通向架构师的道路(第十三天)Axis2 Web Service安全初步 Axis2 Web Service安全是Web服务成功的必要保证。由于Web服务使用XML进行数据交换,而XML在默认情况下是明文编码的,同时,大部分Web服务使用HTTP协议作为...