JAX-WS使用Handler實現簡單的WebService權限驗證

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 [email protected]
 *
 */
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 [email protected]
 *
 */
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;
    }

}


客戶端發起index請求

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();


發佈了91 篇原創文章 · 獲贊 40 · 訪問量 86萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章