WebSerice是一種開放的web服務,任何人都可以訪問,但我們有時候需要考慮只有付費用戶才能使用WS,所以,我們就需要對WS加入安全驗證機制,當然,可以利用防火墻的IP過濾,web應用的配置從最外層去隔離非法用戶,但在內層,我們也可以使用SOAP Header的方式,由客戶端發送驗證數據,服務端驗通過后基WS訪問權限
首先根據我的這篇Blog
http://blog.csdn.net/daryl715/archive/2007/07/25/1707161.aspx
配置WS Server和WS Client,其中Client端的測試代碼類名由Client改為ClientTest,因為我們要用到Xfire的一個名為Client的類
首先我們編寫服務端驗證類繼承AbstractHandler
package test;

import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.handler.AbstractHandler;
import org.jdom.Element;


public class AuthenticationHandler extends AbstractHandler ...{


public void invoke(MessageContext cfx) throws Exception ...{
if(cfx.getInMessage().getHeader() == null)

...{
throw new org.codehaus.xfire.fault.XFireFault("請求必須包含驗證信息",org.codehaus.xfire.fault.XFireFault.SENDER);
}
Element token=cfx.getInMessage().getHeader().getChild("AuthenticationToken");
if (token == null)

...{
throw new org.codehaus.xfire.fault.XFireFault("請求必須包含身份驗證信息", org.codehaus.xfire.fault.XFireFault.SENDER);
}

String username = token.getChild("Username").getValue();
String password = token.getChild("Password").getValue();
try

...{
//進行身份驗證 ,只有abcd@1234的用戶為授權用戶
if(username.equals("abcd") && password.equals("1234"))
//這語句不顯示
System.out.println("身份驗證通過");
else throw new Exception();
}
catch (Exception e)

...{
throw new org.codehaus.xfire.fault.XFireFault("非法的用戶名和密碼", org.codehaus.xfire.fault.XFireFault.SENDER);
}

}



}

下面是Client發送授權信息
package test;

import org.codehaus.xfire.MessageContext;
import org.codehaus.xfire.handler.AbstractHandler;
import org.jdom.Element;


public class ClientAuthenticationHandler extends AbstractHandler ...{

private String username = null;

private String password = null;


public ClientAuthenticationHandler() ...{

}


public ClientAuthenticationHandler(String username,String password) ...{

this.username = username;

this.password = password;
}


public void setUsername(String username) ...{

this.username = username;

}


public void setPassword(String password) ...{

this.password = password;

}


public void invoke(MessageContext context) throws Exception ...{

//為SOAP Header構造驗證信息
Element el = new Element("header");
context.getOutMessage().setHeader(el);
Element auth = new Element("AuthenticationToken");
Element username_el = new Element("Username");
username_el.addContent(username);
Element password_el = new Element("Password");
password_el.addContent(password);
auth.addContent(username_el);
auth.addContent(password_el);
el.addContent(auth);
}



}

為ClientTest.java加入以下代碼
XFireProxy proxy = (XFireProxy)Proxy.getInvocationHandler(service);
Client client = proxy.getClient();
client.addOutHandler(new ClientAuthenticationHandler("abcd1","1234"));
等等,還沒有完,修改Services.xm為WS綁定Handler
<?xml version="1.0" encoding="UTF-8"?>


<beans>
<service xmlns="http://xfire.codehaus.org/config/1.0">
<name>HelloService</name>
<namespace>http://test/HelloService</namespace>
<serviceClass>test.IHelloService</serviceClass>
<implementationClass>test.HelloServiceImpl</implementationClass>
<inHandlers>
<handler handlerClass ="test.AuthenticationHandler" ></handler >
</inHandlers>
</service>
</beans>
這樣我們就完成了編碼,下面啟動tomcat,運行客戶端代碼,本文為abcd@1234位授權用戶,使用abcd@1234,可以正常訪問WS,如果用錯誤帳號,則會有以下異常
Exception in thread "main" org.codehaus.xfire.XFireRuntimeException: Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: 非法的用戶名和密碼
org.codehaus.xfire.fault.XFireFault: 非法的用戶名和密碼
at org.codehaus.xfire.fault.Soap11FaultSerializer.readMessage(Soap11FaultSerializer.java:31)
at org.codehaus.xfire.fault.SoapFaultSerializer.readMessage(SoapFaultSerializer.java:28)
at org.codehaus.xfire.soap.handler.ReadHeadersHandler.checkForFault(ReadHeadersHandler.java:111)
at org.codehaus.xfire.soap.handler.ReadHeadersHandler.invoke(ReadHeadersHandler.java:67)
at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
at org.codehaus.xfire.client.Client.onReceive(Client.java:406)
at org.codehaus.xfire.transport.http.HttpChannel.sendViaClient(HttpChannel.java:139)
at org.codehaus.xfire.transport.http.HttpChannel.send(HttpChannel.java:48)
at org.codehaus.xfire.handler.OutMessageSender.invoke(OutMessageSender.java:26)
at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:79)
at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:114)
at org.codehaus.xfire.client.Client.invoke(Client.java:336)
at org.codehaus.xfire.client.XFireProxy.handleRequest(XFireProxy.java:77)
at org.codehaus.xfire.client.XFireProxy.invoke(XFireProxy.java:57)
at $Proxy0.getUser(Unknown Source)
at test.ClientTest.main(ClientTest.java:39)

如果不在CientTest加以下增加Heade則會有以下異常
XFireProxy proxy = (XFireProxy)Proxy.getInvocationHandler(service);
Client client = proxy.getClient();
client.addOutHandler(new ClientAuthenticationHandler("abcd1","1234"));
Exception in thread "main" org.codehaus.xfire.XFireRuntimeException: Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: 請求必須包含驗證信息
org.codehaus.xfire.fault.XFireFault: 請求必須包含驗證信息
at org.codehaus.xfire.fault.Soap11FaultSerializer.readMessage(Soap11FaultSerializer.java:31)
at org.codehaus.xfire.fault.SoapFaultSerializer.readMessage(SoapFaultSerializer.java:28)
at org.codehaus.xfire.soap.handler.ReadHeadersHandler.checkForFault(ReadHeadersHandler.java:111)
at org.codehaus.xfire.soap.handler.ReadHeadersHandler.invoke(ReadHeadersHandler.java:67)
at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
at org.codehaus.xfire.client.Client.onReceive(Client.java:406)
at org.codehaus.xfire.transport.http.HttpChannel.sendViaClient(HttpChannel.java:139)
at org.codehaus.xfire.transport.http.HttpChannel.send(HttpChannel.java:48)
at org.codehaus.xfire.handler.OutMessageSender.invoke(OutMessageSender.java:26)
at org.codehaus.xfire.handler.HandlerPipeline.invoke(HandlerPipeline.java:131)
at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:79)
at org.codehaus.xfire.client.Invocation.invoke(Invocation.java:114)
at org.codehaus.xfire.client.Client.invoke(Client.java:336)
at org.codehaus.xfire.client.XFireProxy.handleRequest(XFireProxy.java:77)
at org.codehaus.xfire.client.XFireProxy.invoke(XFireProxy.java:57)
at $Proxy0.getUser(Unknown Source)
at test.ClientTest.main(ClientTest.java:35)