首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

Web Service(Axis)的高级运用-Handler,Chain

2012-09-19 
Web Service(Axis)的高级应用--Handler,ChainWeb Service(Axis)的高级应用--Handler,Chain [4]Handler的基

Web Service(Axis)的高级应用--Handler,Chain
Web Service(Axis)的高级应用--Handler,Chain
[4]
Handler的基本概念
J2EE Web 服务中的Handler技术特点非常像Servlet技术中的Filter。我们知道,在Servlet中,当一个
HTTP到达服务端时,往往要经过多个 Filter对请求进行过滤,然后才到达提供服务的Servlet,这些
Filter的功能往往是对请求进行统一编码,对用户进行认证,把用户的访问写入系统日志等。相应的,
Web服务中的Handler通常也提供以下的功能:
对客户端进行认证、授权;
把用户的访问写入系统日志;
对请求的SOAP消息进行加密,解密;
为Web Services对象做缓存。
SOAP消息Handler,能够访问代表RPC请求或者响应的SOAP消息。
使用axisWeb服务开发工具,可以使用Handler来对服务端的请求和响应进行处理。典型的情况下,轴心
点(pivot point)是Apache与提供程序功能相当的部分,通过它来和目标的Web服务进行交互,它通常
称为Provider。axis中常用的 Provider有Java:RPC,java:MSG,java:EJB。一个Web服务可以部署一
个或者多个Handler。
在axis环境下,SOAP消息Handler必须实现org.apache.axis.Handler接口.
为了提供开发的方便,在编写Handler时,只要继承org.apache.axis.handlers. BasicHandler即可,它
是接口Handler的一个实现的抽象类.
BasicHandler中的public abstract void invoke(MessageContext msgContext) 方法是Handler实现类
必须实现的方法,invoke方法是Handler处理其业务的入口点。它通过MessageContext来获得请求或者响
应的SOAPMessage对象,然后对 SOAPMessage进行处理。
(4.1)
使用Handler为系统做日志
Handler为系统做日志是一种比较常见而且简单的使用方式。和Servlet中的Filter一样,我们可以使用
Handler来把用户的访问写入系统日志。
Handler和Chain是Axis引擎提供的一个很强大的工具.假如现在客户有以下需求:
       1.记录来访客户端的IP地址.
       2.记录webservice服务被访问的次数.
       3.以日志的形式记录以上两个信息.
       具体分析下来,该需求并不是很复杂.有几种解决方案:
       1.在所访问的webservice服务中实现一个全局变量,每次有访问,则加1,且取得IP
       2.在访问的入口处记录访问次数和IP
       假设现在对外提供10个webservice服务,那么采用第一种解决方案,势必要重复10次代码.若采用
第二种解决方案,我们只需要实现handler,即可解决所有问题.handler的好处初步显露出来.
如下:
package com.laoer.bbscs.webservice;
public class LogHandler extends BasicHandler {
public void invoke(MessageContext msgContext) throws AxisFault {
  // 每当web服务被调用,都记录到log中。
  try {
   Handler handler = msgContext.getService();
   //LogHandler类中getOption("log")的含义:
   //就是取<parameter name="log" value="appliction.log"/>, 取得的值
为"appliction.log".
   String filename = (String) getOption("log");
   if ((filename == null) || (filename.equals(""))) {
    throw new AxisFault("Server.NoLogFile","No log file
configured for the LogHandler!", null,null);
   }
   String path =
"D:/Eclipse3.2/_Eclipse/bbs/BBSCS_8_0_3/src/com/laoer/bbscs/webservice/";
   FileOutputStream fos = new FileOutputStream(path + 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();
   HttpServletRequest request = (HttpServletRequest) msgContext
     .getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
   msgContext.getMessage().writeTo(System.out);
   String result = "在" + date + ": Web 服务 "
     + msgContext.getTargetService() + " 被来自 "
     + getRealIpAddress(request) + " 调用, 现在已经共调
用了 " + counter
     + " 次.";
   handler.setOption("accesses", counter);
   writer.println(result);
   System.out.println(result);
   writer.close();
  } catch (Exception e) {
   throw AxisFault.makeFault(e);
  }
}

public String getRealIpAddress(HttpServletRequest request) throws Exception {
  String ip = request.getRemoteAddr();
  try {
   ip = request.getHeader("x-forwarded-for");
   if (ip == null || ip.length() == 0
     || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getHeader("Proxy-Client-IP");
   }
   if (ip == null || ip.length() == 0
     || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getHeader("WL-Proxy-Client-IP");
   }
   if (ip == null || ip.length() == 0
     || "unknown".equalsIgnoreCase(ip)) {
    ip = request.getRemoteAddr();
   }
  } catch (Exception ex) {
   throw ex;
  }
  return ip;
}
}
在server-config.wsdd中添加配置:
<!-- 定义全局LogHandler -->
<!-- 该Log用来记录访问者的IP地址等客户端信息 -->
<handler name="Log" type="java:com.laoer.bbscs.webservice.LogHandler"> 
       <parameter name="log" value="application.log"/> 
    </handler>
<service name="WSjLogin" provider="java:RPC">
     <requestFlow> 
         <handler type="Log"/>    
      </requestFlow> 
  <parameter name="className" value="com.laoer.bbscs.webservice.WSjLogin" />
  <parameter name="allowedMethods" value="*" />
</service>
启动TOMCAT,执行客户端调用.生成application.log,且内容:
在Thu Jun 11 20:47:54 CST 2009: Web 服务 WSjLogin 被来自 127.0.0.1 调用, 现在已经共调用了 1
次.
在Thu Jun 11 20:48:30 CST 2009: Web 服务 WSjLogin 被来自 127.0.0.1 调用, 现在已经共调用了 2
次.
在Thu Jun 11 20:48:54 CST 2009: Web 服务 WSjLogin 被来自 127.0.0.1 调用, 现在已经共调用了 3
次.

Handler通过getOption(String)这个方法拿到了配置文件中我配置的属性值,而我们上述所做的所有工作
对于原来的 Webserivce来说都是透明的,不会对侵入原有的程序当中。
一个Handler可以被多个service所使用.通过< requestFlow>这个标签来引用到某一个service中,这里还
要多提一句:既然是一个requestFlow,这个当然可以加不只一个的 Handler。
除了<requestFlow>之外,Axis还提供了与之相应的<responseFlow>,用法和是requestflow一样的,所不同
的是<requestFlow>在service执行之前执行,<responseFlow>是在service之后执行的。
(4.2)
用户简单验证:
1)
添加验证的Handler:
package com.laoer.bbscs.webservice;
public class UserAuthentizationHandler extends BasicHandler {
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) {
   //从soap消息中取得用户名及密码
   String userId = msgContext.getUsername();
   String password=msgContext.getPassword();
// 对用户进行认证,如果authUser==null,表示没有通过认证,抛出Server.Unauthenticated异常。
   AuthenticatedUser authUser = provider.authenticate(msgContext);
   if (authUser == null)
    throw new AxisFault("Server.Unauthenticated",
Messages.getMessage("cantAuth01", userId), null, null);
   // 用户通过认证,把用户的设置成认证了的用户。
   msgContext.setProperty("authenticatedUser", authUser);
   System.out.println( authUser.getName() + " 通过身份验证! ");
  }
}
}
2)
在server-config.wsdd中添加配置:
    <handler name="UserAuthentization"
             type="java:com.laoer.bbscs.webservice.UserAuthentizationHandler" />
<service name="WSjLogin" provider="java:RPC">
     <requestFlow> 
         <handler type="Log"/>  
         <handler type="UserAuthentization"/> 
      </requestFlow> 
  <parameter name="className" value="com.laoer.bbscs.webservice.WSjLogin" />
  <parameter name="allowedMethods" value="*" />
</service>
3)
在服务端/web-inf/users.lst中添加相应的用户名及密码:
jason 1234
在客户端的调用程序中设置用户名及密码:
public class WSGetJlogin {
public static void main(String[] args)
{
  String endpoint="http://localhost:8080/BBSCS_8_0_3/services/WSjLogin";
  try {
   Service service=new Service();
   Call call=(Call)service.createCall();
   call.setTargetEndpointAddress(endpoint);
   call.setOperationName("getMessage");
   call.getMessageContext().setUsername("jason");  --此处设置
   call.getMessageContext().setPassword("1234");
   String bbscsPassword=(String)call.invoke(new Object[]{"hello"});
   System.out.println(bbscsPassword);
  } catch (Exception e) {
   e.printStackTrace();
  }
}
}
执行的过程是:
客户端程序在调用服务端方法之前,向soap中设置了Username和Passname.
服务端UserAuthentizationHandler类中调用provider.authenticate(msgContext)该方法,会从
msgContext取得客户端传来的username,password同users中对应的key-value比较.users是个HashMap,在
初始化方法中读users.lst这个文件.由此可知,我们必须在服务端存放一个users.lst文件,来保存用户名
和密码.在应用的 */WEB-INF/目录下创建users.lst文件.

关于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
     使用SSL/HTTPS协议来传输

[5]
我们再来认识一下chain.
Chain可以理解为它实现的一连串Handler的功能,就是多个Handler的集合.
package chain;
//SimpleChain是继承BasicHandler的
public class SecurityChain extends SimpleChain{
    public SecurityChain(){  
     UserAuthentizationHandler user = new UserAuthentizationHandler();  
        LogHandler log = new LogHandler();  
        this.addHandler(user);  
        this.addHandler(log);  
    }
}
在server-config.wsdd在添加:
    <chain name="SecurityChain">
       <handler type="java:com.laoer.bbscs.webservice.SecurityChain" />
    </chain>
<service name="WSjLogin" provider="java:RPC">
     <requestFlow> 
         <!-- <handler type="Log"/>   -->
         <!-- <handler type="UserAuthentization"/> -->
         <chain type="SecurityChain"/>
      </requestFlow> 
  <parameter name="className" value="com.laoer.bbscs.webservice.WSjLogin" />
  <parameter name="allowedMethods" value="*" />
  <parameter name="scope" value="session" />
</service>
本文出自 51CTO.COM技术博客

热点排行
Bad Request.