JAX-WS使用Handler实现简单的WebService权限验证
WebService如果涉及到安全保密或者使用權限的時候,WS-Security通常是最優選擇。WS-Security (Web服務安全)
包含了關于如何在WebService消息上保證完整性和機密性的規約,如何將簽名和加密頭加入SOAP消息。
不過WS-Security也有一些性能上的損耗,在信息保密要求不是很高的情況下,可以通過在SOAPHeader中添加簡單的校驗信息實現。
具體思路是客戶端調用需要認證的服務時,在SOAPHeader中添加授權信息(如用戶名、密碼或者序列號等)。
服務端收到請求,在SOAPHeader中校驗授權信息,校驗通過則執行請求,校驗不通過則返回錯誤提示。
客戶端發起請求在SOAPHeader中添加的授權數據格式如下
<auth xmlns="http://schemas.xmlsoap.org/soap/actor/next"> <username>admin</username> <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.SOAPConstants; 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;import org.apache.cxf.interceptor.Fault; import org.w3c.dom.NodeList;/**** @author */ public class JaxServerAuthValidateHeader implements SOAPHandler<SOAPMessageContext> {@Overridepublic void close(MessageContext context) {}@Overridepublic boolean handleFault(SOAPMessageContext context) {return true;}@Overridepublic boolean handleMessage(SOAPMessageContext context) {// 判斷消息是輸入還是輸出boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);SOAPMessage soapMessage = context.getMessage();if (!isRequest) {SOAPHeader soapHeader = null;try {SOAPEnvelope soapEnv = soapMessage.getSOAPPart().getEnvelope();soapHeader = soapEnv.getHeader();} catch (SOAPException e) {throw new Fault(new Exception("服務器異常!"));}if (soapHeader == null) {validateFail(soapMessage, "無 Soap Header 頭信息!");return false;}// add an node named "auth"QName qname = new QName(SOAPConstants.URI_SOAP_ACTOR_NEXT, "auth");Iterator<?> iterator = soapHeader.getChildElements(qname);SOAPElement auth = null;if (iterator.hasNext()) {// 獲取authauth = (SOAPElement) iterator.next();}// 如果授權信息元素不存在,提示錯誤if (auth == null) {validateFail(soapMessage, "無授權信息!");return false;}NodeList nameList = auth.getElementsByTagName("username");NodeList pwdList = auth.getElementsByTagName("password");if (nameList == null || nameList.getLength() <= 0 || pwdList == null || pwdList.getLength() <= 0) {validateFail(soapMessage, "授權信息格式錯誤!");return false;}String username = nameList.item(0).getTextContent();String password = pwdList.item(0).getTextContent();if (!"admin".equals(username) || !"admin".equals(password)) {validateFail(soapMessage, "授權信息格式錯誤!");return false;}}System.out.println(isRequest ? "服務端響應:" : "服務端接收:");System.out.println("\r\n");return true;}@Overridepublic Set<QName> getHeaders() {return null;}/*** 授權校驗失敗,在SOAPBody中添加SOAPFault* * @param message*/private void validateFail(SOAPMessage soapMessage, String faultString) {try {SOAPEnvelope envelop = soapMessage.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(faultString);soapMessage.saveChanges();} catch (SOAPException e) {e.printStackTrace();}}}服務端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.server.handler.JaxServerAuthValidateHeader</javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>服務端的Service中添加Handler配置文件?
import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.ws.RequestWrapper; import javax.xml.ws.ResponseWrapper;/*** This class was generated by Apache CXF 3.2.1* 2017-12-01T14:12:00.085+08:00* Generated source version: 3.2.1* */ @WebService(targetNamespace = "http://tempuri.org/", name = "AExampleDemoWebService") @HandlerChain(file="handler-chain.xml") public interface AExampleDemoWebService {@WebMethod@WebResult(name = "single", targetNamespace = "")public java.lang.String querySingle(@WebParam(name = "single", targetNamespace = "http://tempuri.org/")java.lang.String single);}服務端的Service 實現類
import java.util.ArrayList; import java.util.List;import cn.evun.iwm.receive.soap.service.AExampleDemoWebService; import cn.evun.iwm.receive.soap.struc.sample.InputParam; import cn.evun.iwm.receive.soap.struc.sample.OutputParam;@javax.jws.WebService(serviceName = "aexampleDemoWebService", portName = "Sample", targetNamespace = "http://tempuri.org/", endpointInterface = "cn.soap.service.AExampleDemoWebService") public class AExampleDemoWebServiceImpl implements AExampleDemoWebService {@Overridepublic String querySingle(String input) {return "success";}}客戶端
客戶端添加授權Handler
import java.io.IOException; import java.util.Set;import javax.xml.namespace.QName; import javax.xml.soap.SOAPConstants; 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;public class JaxWsClientHandler implements SOAPHandler<SOAPMessageContext> {@Overridepublic boolean handleMessage(SOAPMessageContext context) {// 判斷消息是請求還是響應Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);SOAPMessage soapMessage = context.getMessage();if (isRequest) {try {SOAPHeader soapHeader = soapMessage.getSOAPHeader(); if (soapHeader == null) { soapHeader = soapMessage.getSOAPPart().getEnvelope().addHeader(); } // add an node named "auth"QName qname = new QName(SOAPConstants.URI_SOAP_ACTOR_NEXT, "auth");SOAPElement auth = soapHeader.addChildElement(qname);SOAPElement name = auth.addChildElement("username");name.addTextNode("admin");SOAPElement password = auth.addChildElement("password");password.addTextNode("admin");soapMessage.saveChanges();// tracking soapMessage.writeTo(System.out);} catch (SOAPException e) {System.err.println(e);} catch (IOException e) {System.err.println(e);}}return true;}@Overridepublic boolean handleFault(SOAPMessageContext context) {return false;}@Overridepublic void close(MessageContext context) {}@Overridepublic 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.client.handler.JaxWsClientHandler</javaee:handler-class> </javaee:handler> </javaee:handler-chain> </javaee:handler-chains>客戶端的Service中添加Handler配置文件
import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.WebEndpoint; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceFeature;import javax.xml.ws.Service;/*** This class was generated by Apache CXF 3.2.1* 2017-12-01T14:12:00.117+08:00* Generated source version: 3.2.1* */ @WebServiceClient(name = "aexampleDemoWebService", wsdlLocation = "http://localhost:8090/service/Sample?wsdl",targetNamespace = "http://tempuri.org/") @HandlerChain(file="handler-chain.xml") public class AexampleDemoWebServiceSoap extends Service {public final static URL WSDL_LOCATION;public final static QName SERVICE = new QName("http://tempuri.org/", "aexampleDemoWebService");public final static QName Sample = new QName("http://tempuri.org/", "Sample");static {URL url = null;try {url = new URL("http://localhost:8090/service/Sample?wsdl");} catch (MalformedURLException e) {java.util.logging.Logger.getLogger(AexampleDemoWebServiceSoap.class.getName()).log(java.util.logging.Level.INFO, "Can not initialize the default wsdl from {0}", "http://localhost:8090/service/Sample?wsdl");}WSDL_LOCATION = url;}public AexampleDemoWebServiceSoap(URL wsdlLocation) {super(wsdlLocation, SERVICE);}public AexampleDemoWebServiceSoap(URL wsdlLocation, QName serviceName) {super(wsdlLocation, serviceName);}public AexampleDemoWebServiceSoap() {super(WSDL_LOCATION, SERVICE);}public AexampleDemoWebServiceSoap(WebServiceFeature ... features) {super(WSDL_LOCATION, SERVICE, features);}public AexampleDemoWebServiceSoap(URL wsdlLocation, WebServiceFeature ... features) {super(wsdlLocation, SERVICE, features);}public AexampleDemoWebServiceSoap(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) {super(wsdlLocation, serviceName, features);} /**** @return* returns AExampleDemoWebService*/@WebEndpoint(name = "Sample")public AExampleDemoWebService getSample() {return super.getPort(Sample, AExampleDemoWebService.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 AExampleDemoWebService*/@WebEndpoint(name = "Sample")public AExampleDemoWebService getSample(WebServiceFeature... features) {return super.getPort(Sample, AExampleDemoWebService.class, features);}}
客戶端發起請求
QName SERVICE_NAME = new QName("http://tempuri.org/", "aexampleDemoWebService"); URL url = new URL("http://localhost:8090/service/Sample?wsdl"); AexampleDemoWebServiceSoap ss = new AexampleDemoWebServiceSoap(wsdlURL, SERVICE_NAME); AExampleDemoWebService port = ss.getSample(); port.querySingle("1111");@HandlerChain 注解 替代方式
客戶端 ?通過 HandlerReolver 代替?@HandlerChain 注解 導入?Handler 配置文件
handler-chain配置文件對所有的請求都添加授權驗證信息,有些時候不是所有的請求都需要添加授權驗證,HandlerResolver提供了在編程時添加Handler的方法,可以用HandlerResolver給需要授權的接口添加Handler。
QName SERVICE_NAME = new QName("http://tempuri.org/", "aexampleDemoWebService"); URL url = new URL("http://localhost:8090/service/Sample?wsdl"); AexampleDemoWebServiceSoap ss = new AexampleDemoWebServiceSoap(wsdlURL, SERVICE_NAME); //通過HandlerResolver添加Handler ss.setHandlerResolver(new HandlerResolver(){ @Override @SuppressWarnings("rawtypes") public List<Handler> getHandlerChain(PortInfo portInfo) { List<Handler> handlerChain = new ArrayList<Handler>(); handlerChain.add(new JaxWsClientHandler()); return handlerChain; } }); AExampleDemoWebService port = ss.getSample(); port.querySingle("2222");服務端?@HandlerChain 注解替代?
服務發布時服務端通過繼承至?Endpoint 實現類?EndpointImpl 的?setHandlers 方法添加頭部信息?代替?@HandlerChain 注解?導入?Handler 配置文件
import java.util.ArrayList; import java.util.List;import javax.xml.ws.Endpoint; import javax.xml.ws.handler.Handler;import org.apache.cxf.Bus; import org.apache.cxf.bus.spring.SpringBus; import org.apache.cxf.interceptor.Interceptor; import org.apache.cxf.jaxws.EndpointImpl; import org.apache.cxf.message.Message; import org.apache.cxf.transport.servlet.CXFServlet; import org.springframework.boot.context.embedded.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;@Configuration public class CXFConfig {@Beanpublic ServletRegistrationBean dispatcherServlet() {return new ServletRegistrationBean(new CXFServlet(), "/service/*");}@Bean(name = Bus.DEFAULT_BUS_ID)public SpringBus springBus() {return new SpringBus();}@Beanpublic AExampleDemoWebServiceImpl aExampleDemoWebServiceImpl() {return new AExampleDemoWebServiceImpl();}@Beanpublic Endpoint endpointWebServiceSampleImpl() {EndpointImpl endpoint = new EndpointImpl(springBus(), aExampleDemoWebServiceImpl());// SOAPHandler 方式 @SuppressWarnings("rawtypes")List<Handler> handlers = new ArrayList<>();handlers.add(new JaxServerAuthValidateHeader());endpoint.setHandlers(handlers);endpoint.publish("/Sample");return endpoint;}}當使用替代方式添加頭部信息的時候就不需要使用?@HandlerChain 注解?
轉載于:https://www.cnblogs.com/rinack/p/7943164.html
總結
以上是生活随笔為你收集整理的JAX-WS使用Handler实现简单的WebService权限验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 军事夏令营的费用是多少?
- 下一篇: 关于字符串属性的几道面试题目