WebService假设涉及到安全保密或者使用权限的时候,WS-Security一般是最优选择。WS-Security (Web服务安全) 包括了关于怎样在WebService消息上保证完整性和机密性的规约,怎样将签名和加密头加入SOAP消息。只是WS-Security也有一些性能上的损耗,在信息保密要求不是非常高的情况下,能够通过在SOAPHeader中加入简单的校验信息实现。
详细思路是client调用须要认证的服务时,在SOAPHeader中加入授权信息(如username、password或者序列号等)。服务端收到请求,在SOAPHeader中校验授权信息,校验通过则运行请求,校验不通过则返回错误提示。
实例代码
http://download.csdn.net/detail/accountwcx/8922191
client发起请求在SOAPHeader中加入的授权数据格式例如以下
<auth xmlns="http://www.tmp.com/auth"> <name>admin</name> <password>admin</password> </auth>
服务端
服务端授权校验Handler
import java.util.Iterator; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPFault; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; /** * 服务端请求校验Handler * @author accountwcx@qq.com * */ public class ValidateAuthHandler implements SOAPHandler<SOAPMessageContext> { @Override public void close(MessageContext context) { } @Override public boolean handleFault(SOAPMessageContext context) { return true; } @Override public boolean handleMessage(SOAPMessageContext context) { // 推断消息是请求还是响应 Boolean output = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); boolean result = false; SOAPMessage message = context.getMessage(); //假设是请求,则运行校验 if(!output){ result = validate(message); if(!result){ validateFail(message); } } System.out.println(output ?"服务端响应:" : "服务端接收:"); try { message.writeTo(System.out); } catch (Exception e) { e.printStackTrace(); } System.out.println(" "); return result; } /** * 授权校验失败,在SOAPBody中加入SOAPFault * @param message */ private void validateFail(SOAPMessage message) { try { SOAPEnvelope envelop = message.getSOAPPart().getEnvelope(); envelop.getHeader().detachNode(); envelop.addHeader(); envelop.getBody().detachNode(); SOAPBody body = envelop.addBody(); SOAPFault fault = body.getFault(); if (fault == null) { fault = body.addFault(); } fault.setFaultString("授权校验失败!"); message.saveChanges(); } catch (SOAPException e) { e.printStackTrace(); } } /** * 授权校验 * @param message * @return 校验成功返回true。校验失败返回false */ private boolean validate(SOAPMessage message){ boolean result = false; try { SOAPEnvelope envelop = message.getSOAPPart().getEnvelope(); SOAPHeader header = envelop.getHeader(); if(header != null){ Iterator iterator = header.getChildElements(new QName("http://www.tmp.com/auth", "auth")); SOAPElement auth = null; if(iterator.hasNext()){ //获取auth auth = (SOAPElement)iterator.next(); //获取name Iterator it = auth.getChildElements(new QName("http://www.tmp.com/auth", "name")); SOAPElement name = null; if(it.hasNext()){ name = (SOAPElement)it.next(); } //获取password it = auth.getChildElements(new QName("http://www.tmp.com/auth", "password")); SOAPElement password = null; if(it.hasNext()){ password = (SOAPElement)it.next(); } //推断name和password是否符合要求 if(name != null && password != null && "admin".equals(name.getValue()) && "admin".equals(password.getValue())){ result = true; } } } } catch (SOAPException e) { e.printStackTrace(); } return result; } @Override public Set<QName> getHeaders() { return null; } }
client
client加入授权Handler
import java.util.Set; import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; /** * client加入请求授权 * @author accountwcx@qq.com * */ public class AddAuthHandler implements SOAPHandler<SOAPMessageContext> { @Override public boolean handleMessage(SOAPMessageContext context) { // 推断消息是请求还是响应 Boolean output = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = context.getMessage(); if (output) { try { SOAPHeader header = message.getSOAPHeader(); if (header == null) { header = message.getSOAPPart().getEnvelope().addHeader(); } SOAPElement auth = header.addChildElement(new QName("http://www.tmp.com/auth", "auth")); SOAPElement name = auth.addChildElement("name"); name.addTextNode("admin"); SOAPElement password = auth.addChildElement("password"); password.addTextNode("admin"); message.saveChanges(); } catch (SOAPException e) { e.printStackTrace(); } } System.out.println(output ?"client请求:" : "client接收:"); try { message.writeTo(System.out); } catch (Exception e) { e.printStackTrace(); } System.out.println(" "); return true; } @Override public boolean handleFault(SOAPMessageContext context) { return true; } @Override public void close(MessageContext context) { } @Override public Set<QName> getHeaders() { return null; } }
clientHandler配置文件handler-chain.xml
<?xml version="1.0" encoding="UTF-8"?> <javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <javaee:handler-chain> <javaee:handler> <javaee:handler-class>com.rvho.client.handler.AddAuthHandler</javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>
client的Service中加入Handler配置文件
/** * This class was generated by the JAX-WS RI. * JAX-WS RI 2.2.9-b130926.1035 * Generated source version: 2.2 * */ @WebServiceClient(name = "HelloWSService", targetNamespace = "http://www.tmp.com/ws/hello", wsdlLocation = "http://localhost:8014/jaxwsserver/services/hello?wsdl") @HandlerChain(file="handler-chain.xml") public class HelloWSService extends Service { private final static URL HELLOWSSERVICE_WSDL_LOCATION; private final static WebServiceException HELLOWSSERVICE_EXCEPTION; private final static QName HELLOWSSERVICE_QNAME = new QName("http://www.tmp.com/ws/hello", "HelloWSService"); static { URL url = null; WebServiceException e = null; try { url = new URL("http://localhost:8014/jaxwsserver/services/hello?wsdl"); } catch (MalformedURLException ex) { e = new WebServiceException(ex); } HELLOWSSERVICE_WSDL_LOCATION = url; HELLOWSSERVICE_EXCEPTION = e; } public HelloWSService() { super(__getWsdlLocation(), HELLOWSSERVICE_QNAME); } public HelloWSService(WebServiceFeature... features) { super(__getWsdlLocation(), HELLOWSSERVICE_QNAME, features); } public HelloWSService(URL wsdlLocation) { super(wsdlLocation, HELLOWSSERVICE_QNAME); } public HelloWSService(URL wsdlLocation, WebServiceFeature... features) { super(wsdlLocation, HELLOWSSERVICE_QNAME, features); } public HelloWSService(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public HelloWSService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { super(wsdlLocation, serviceName, features); } /** * * @return * returns HelloWS */ @WebEndpoint(name = "HelloWSPort") public HelloWS getHelloWSPort() { return super.getPort(new QName("http://www.tmp.com/ws/hello", "HelloWSPort"), HelloWS.class); } /** * * @param features * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values. * @return * returns HelloWS */ @WebEndpoint(name = "HelloWSPort") public HelloWS getHelloWSPort(WebServiceFeature... features) { return super.getPort(new QName("http://www.tmp.com/ws/hello", "HelloWSPort"), HelloWS.class, features); } private static URL __getWsdlLocation() { if (HELLOWSSERVICE_EXCEPTION!= null) { throw HELLOWSSERVICE_EXCEPTION; } return HELLOWSSERVICE_WSDL_LOCATION; } }
URL wsdlUrl = new URL("http://localhost:7180/jaxwsserver/services/hello?wsdl"); HelloWSService helloWSS = new HelloWSService(wsdlUrl); HelloWS helloWS = helloWSS.getHelloWSPort(); String index = helloWS.index();
client发起正确授权的请求以及server的响应
<!-- client请求 --> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header> <auth xmlns="http://www.tmp.com/auth"> <name>admin</name> <password>admin</password> </auth> </SOAP-ENV:Header> <S:Body> <ns2:index xmlns:ns2="http://www.tmp.com/ws/hello" /> </S:Body> </S:Envelope> <!-- 服务端响应 --> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <S:Body> <ns2:indexResponse xmlns:ns2="http://www.tmp.com/ws/hello"> <return>hello</return> </ns2:indexResponse> </S:Body> </S:Envelope>
client发起错误授权的请求以及server的响应
<!-- client请求 --> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header> <auth xmlns="http://www.tmp.com/auth"> <name></name> <password></password> </auth> </SOAP-ENV:Header> <S:Body> <ns2:index xmlns:ns2="http://www.tmp.com/ws/hello" /> </S:Body> </S:Envelope> <!-- server响应 --> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header/> <S:Body> <S:Fault> <faultcode>S:Server</faultcode> <faultstring>授权校验失败!</faultstring> </S:Fault> </S:Body> </S:Envelope>
HandlerReolver取代Handler配置文件
handler-chain配置文件对全部的请求都加入授权验证信息,有些时候不是全部的请求都须要加入授权验证,HandlerResolver提供了在编程时加入Handler的方法,能够用HandlerResolver给须要授权的接口加入Handler。
URL wsdlUrl = new URL("http://localhost:7180/jaxwsserver/services/hello?wsdl"); HelloWSService helloWSS = new HelloWSService(wsdlUrl); //通过HandlerResolver加入Handler helloWSS.setHandlerResolver(new HandlerResolver(){ @Override @SuppressWarnings("rawtypes") public List<Handler> getHandlerChain(PortInfo portInfo) { List<Handler> handlerChain = new ArrayList<Handler>(); handlerChain.add(new AddAuthHandler()); return handlerChain; } }); HelloWS helloWS = helloWSS.getHelloWSPort(); //调用index服务 String index = helloWS.index();