第一天裏說了如何用jax-ws去結合ssh框架。java
在今天的教程中將會向你們詳細講述一個ws-security中的一個傳統的」基於handler」來認證客戶端傳來的用戶名密碼的webservice.node
客戶端傳過來一對用戶名和密碼,服務端進行認證。web
固然,咱們此處說這個用戶名和密碼的傳送,那可不是用下面的這種形式來傳送的哦: http://xxx.do?username=xxx&password=xxx。apache
咱們這個用戶名和密碼是帶在soap報文中的, jax-ws用一個handler專門用於處理soap報文的。tomcat
package ctsjavacoe.ws.fromjava;框架 import java.util.*;ssh import javax.servlet.http.HttpServletRequest;url import javax.xml.namespace.QName;spa import javax.xml.soap.*;.net import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.*; import javax.xml.ws.soap.SOAPFaultException; import org.apache.cxf.transport.http.*; public class AuthValidationHandler implements SOAPHandler<SOAPMessageContext> { public Set<QName> getHeaders() { // TODO Auto-generated method stub return null; } public void close(MessageContext context) { } public boolean handleFault(SOAPMessageContext context) { return false; } public boolean handleMessage(SOAPMessageContext context) {
HttpServletRequest request = (HttpServletRequest) context .get(AbstractHTTPDestination.HTTP_REQUEST); // if (request != null) { System.out.println("Client IP:" + request.getRemoteAddr()); } else { System.out.println("get client ip is null>>>>>>>>>"); }
Boolean outbound = (Boolean) context .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!outbound.booleanValue()) { SOAPMessage soapMessage = context.getMessage();
try { SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart() .getEnvelope(); SOAPHeader soapHeader = soapEnvelope.getHeader();
if (soapHeader == null) generateSoapFault(soapMessage, "No Message Header...");
Iterator it = soapHeader .extractHeaderElements(SOAPConstants.URI_SOAP_1_2_ROLE_NEXT);
if (it == null || !it.hasNext()) generateSoapFault(soapMessage, "No Header block for role next");
Node node = (Node) it.next();
String value = node == null ? null : node.getValue();
if (value == null) generateSoapFault(soapMessage, "No authation info in header blocks");
String[] infos = value.split("&");
return authValidate(infos[0], infos[1]);
} catch (SOAPException e) { e.printStackTrace(); }
} return false; } private boolean authValidate(String userName, String password) { if (userName == null || password == null) { return false; }
if ("admin".equals(userName) && "admin".equals(password)) { return true; } return false; }
private void generateSoapFault(SOAPMessage soapMessage, String reasion) { try { SOAPBody soapBody = soapMessage.getSOAPBody(); SOAPFault soapFault = soapBody.getFault();
if (soapFault == null) { soapFault = soapBody.addFault(); }
soapFault.setFaultString(reasion);
throw new SOAPFaultException(soapFault);
} catch (SOAPException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
} |
上面這段代碼看似很長,其實邏輯很簡單,注意:
publicboolean handleMessage(SOAPMessageContext context)這個方法。
Handler會先檢查,這個soap是in仍是out,固然,對於咱們來講要驗證客戶端提交上來的用戶名和密碼,因該是in。
所以,若是這個soap是in,而且含有soapheader(咱們的用戶名密碼是含在soap header中的,可不是經過url以http://xxx.xxx.xxx/xxx.do?username=xxx&password=xxx這樣的形式傳輸的哦,這樣作是徹頭徹尾的做弊,不對的做法,和掩耳盜鈴沒啥區別),而且含有soap header,這個soap header中會提取出「username&password」這樣的一個字符串,而後進行用戶名和密碼的比對與校驗。
咱們有了Handler類,還須要有一個handler的xml文件,對該類進行描述,這個xml文件和handler類放在同一層java的package下,該XML名爲:handlers.xml,內容以下:
<?xml version="1.0" encoding="UTF-8"?> <handler-chains xmlns="http://java.sun.com/xml/ns/javaee"> <handler-chain> <handler> <handler-name>authHandler</handler-name> <handler-class> ctsjavacoe.ws.fromjava.AuthValidationHandler </handler-class> </handler> </handler-chain> </handler-chains> |
package ctsjavacoe.ws.fromjava; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @SOAPBinding(style = Style.RPC) public interface AuthorServer { @WebMethod public String sayHello(String name); } |
package ctsjavacoe.ws.fromjava;
import javax.jws.HandlerChain; import javax.jws.WebService; @WebService(endpointInterface = "ctsjavacoe.ws.fromjava.AuthorServer") @HandlerChain(file = "handlers.xml") public class AuthorServerImpl implements AuthorServer { public String sayHello(String name) { return "Hello: " + name; } } |
核心是這一行:@HandlerChain(file= "handlers.xml")。
把它編譯成webservice,而後發佈工程到tomcat中去吧。
獲得wsdl: http://localhost:8080/JaxWSSample/AuthorServerService?wsdl
咱們用SOAPUI來調用這個webservice試試效果:
你們能夠看到入到的output是:<faultstring>No Header blockfor role next</faultstring>
根據wsdl先獲得相關的stub。
package ctsjavacoe.ws.fromjava; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.*; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class ClientAuthenticationHandler implements SOAPHandler<SOAPMessageContext> { public Set<QName> getHeaders() { // TODO Auto-generated method stub return null; } public void close(MessageContext arg0) { // TODO Auto-generated method stub } public boolean handleFault(SOAPMessageContext arg0) { // TODO Auto-generated method stub return false; } public boolean handleMessage(SOAPMessageContext ctx) { Boolean request_p = (Boolean) ctx .get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (request_p) { try { SOAPMessage msg = ctx.getMessage(); SOAPEnvelope env = msg.getSOAPPart().getEnvelope(); SOAPHeader hdr = env.getHeader();
if (hdr == null) hdr = env.addHeader();
QName qname_user = new QName("http://fromjava.ws.ctsjavacoe/", "AuthorServerImplService"); SOAPHeaderElement helem_user = hdr.addHeaderElement(qname_user); helem_user.setActor(SOAPConstants.URI_SOAP_1_2_ROLE_NEXT); helem_user.addTextNode("admin&admin1"); msg.saveChanges(); //msg.writeTo(System.out); return true; } catch (Exception e) { e.printStackTrace(); } } return false; } } |
該handler類主要的核心方法爲:
public booleanhandleMessage(SOAPMessageContext ctx)方法
該方法中須要注意的是:
QName qname_user = new QName("http://fromjava.ws.ctsjavacoe/", "AuthorServerImplService"); SOAPHeaderElement helem_user = hdr.addHeaderElement(qname_user); helem_user.setActor(SOAPConstants.URI_SOAP_1_2_ROLE_NEXT); helem_user.addTextNode("admin&admin1"); msg.saveChanges(); |
咱們經過上述的語句就已經知道咱們會在客戶端傳過去一對用戶名與密碼,它們是:
username=admin
password=admin1
package ctsjavacoe.ws.fromjava;
import java.util.*;
import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.HandlerResolver; import javax.xml.ws.handler.PortInfo; public class AuthorServerClient { public static void main(String[] args) { AuthorServerImplService service = new AuthorServerImplService(); service.setHandlerResolver(new HandlerResolver() { public List<Handler> getHandlerChain(PortInfo arg0) { List<Handler> handlerList = new ArrayList<Handler>(); handlerList.add(new ClientAuthenticationHandler()); return handlerList; } }); AuthorServer authorService = service.getAuthorServerImplPort(); String msg = authorService.sayHello("MK"); System.out.println("rtn msg=====" + msg); } } |
運行後咱們獲得了以下的輸出:
出錯了?爲何?
咱們回過頭來看兩個handler,一個是server端的handler,其中:
if ("admin".equals(userName) && "admin".equals(password)) { return true; } |
一個是client的handler類,其中:
helem_user.addTextNode("admin&admin1"); |
啊。。。由於server端的密碼要求是」admin」不是」admin1」,因而咱們把client端的密碼也改爲」admin」,再次運行咱們的客戶端,獲得輸出:
完成次日的教程