WebService如果涉及到安全保密或者使用权限的时候,WS-Security通常是最优选择。WS-Security (Web服务安全) 包含了关于如何在WebService消息上保证完整性和机密性的规约,如何将签名和加密头加入SOAP消息。不过WS-Security也有一些性能上的损耗,在信息保密要求不是很高的情况下,可以通过在SOAPHeader中添加简单的校验信息实现。
具体思路是客户端调用需要认证的服务时,在SOAPHeader中添加授权信息(如用户名、密码或者序列号等)。服务端收到请求,在SOAPHeader中校验授权信息,校验通过则执行请求,校验不通过则返回错误提示。
实例代码 http://download.csdn.net/detail/accountwcx/8922191
客户端发起请求在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("\r\n");
- 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;
- }
- }
客户端
客户端添加授权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;
- /**
- * 客户端添加请求授权
- * @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 ? "客户端请求:" : "客户端接收:");
- try {
- message.writeTo(System.out);
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("\r\n");
- return true;
- }
- @Override
- public boolean handleFault(SOAPMessageContext context) {
- return true;
- }
- @Override
- public void close(MessageContext context) {
- }
- @Override
- public Set<QName> getHeaders() {
- return null;
- }
- }
客户端Handler配置文件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>
客户端的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();
客户端发起正确授权的请求以及服务器的响应
- <!-- 客户端请求 -->
- <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>
客户端发起错误授权的请求以及服务器的响应
- <!-- 客户端请求 -->
- <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>
- <!-- 服务器响应 -->
- <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();