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技术博客
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值