在soapheader中添加自定义信息
发布时间:2020-12-17 01:05:48 所属栏目:安全 来源:网络整理
导读:? ? ? ? 有时候我们的webservice在服务端需要做一个调用方的验证,以保证我们的服务只有指定的客户才能使用。虽然可以使用wss4j的方法来做安全验证, 但是考虑到我们的项目会与被.net平台下的项目调用,为了避免跨平台间出现的问题,我们还是决定采用自定义s
? ? ? ? 有时候我们的webservice在服务端需要做一个调用方的验证,以保证我们的服务只有指定的客户才能使用。虽然可以使用wss4j的方法来做安全验证,但是考虑到我们的项目会与被.net平台下的项目调用,为了避免跨平台间出现的问题,我们还是决定采用自定义soapheader的形式来添加验证信息。 ? ? ? ? ? ?先来看一下客户端发起请求的soap内容 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:apac="http://apache.org/"> <soapenv:Header/> <soapenv:Body> <apac:CyfTest> <!--Optional:--> <arg0>?</arg0> <!--Optional:--> <arg1>?</arg1> </apac:CyfTest> </soapenv:Body> </soapenv:Envelope>其中红字部分就是我们要添加自定义信息的位置,再来看一下客户端的spring配置文件 <bean id="TsbServiceFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="address" value="http://localhost:8080/TsbWebService/Cyf?wsdl"></property> <property name="serviceClass" value="tsb.ws.tsbinterface.ICyfClient"></property> <property name="outInterceptors"> <list> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> <bean class="tsb.ws.common.authentication.AddPptSoapHeader"></bean> </list> </property> </bean>其中红色部分指定的类就是用来在请求的soap协议中加上自定义头部信息的处理类,处理类内容如下 package tsb.ws.common.authentication; import java.util.List; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapHeader; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.headers.Header; import org.apache.cxf.helpers.DOMUtils; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.Phase; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * 添加SoapHeader拦截器 * @author cyf * */ public class AddSoapHeader extends AbstractSoapInterceptor { public AddSoapHeader() { super(Phase.WRITE); } /** * 处理soap信息 * @param message soap信息 * <P>作成者:cyf */ public void handleMessage(SoapMessage message) throws Fault { // SoapHeader部分待添加的节点 QName qName = new QName("CertificationProxy"); Document doc = DOMUtils.createDocument(); // 验证用户名 Element id = doc.createElement("userid"); id.setTextContent("xxx"); // 验证密码 Element pwd = doc.createElement("userpwd"); pwd.setTextContent("xxx"); Element root = doc.createElementNS("http://tempuri.org/","CertificationProxy"); root.appendChild(id); root.appendChild(pwd); // 创建SoapHeader内容 SoapHeader header = new SoapHeader(qName,root); // 添加SoapHeader内容 List<Header> headers = message.getHeaders(); headers.add(header); } } 在调用服务的时候客户端就可以在soap请求的头部添加如下的信息其中userid和userpwd就是我们用来验证的用户名和密码 <?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:apac="http://apache.org/"> <soapenv:Header> <CertificationProxy xmlns="http://tempuri.org/"> <userid>xxx</userid> <userpwd>xxx</userpwd> </CertificationProxy> </soapenv:Header> <soapenv:Body> <apac:CyfTest> <!--Optional: --> <arg0>?</arg0> <!--Optional: --> <arg1>?</arg1> </apac:CyfTest> </soapenv:Body> </soapenv:Envelope> 服务端截取请求soap协议时需要在配置文件中添加拦截器 <jaxws:endpoint id="TsbWebService" implementor="tsb.ws.tsbimpl.TsbWebServiceImpl" address="/Tsb"> <jaxws:inInterceptors> <!-- 日志拦截器 --> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> <!-- 自定义拦截器,用于实现认证操作 --> <bean class="tsb.ws.common.authentication.ReadSoapHeader" /> </jaxws:inInterceptors> <jaxws:serviceFactory> <ref bean="jaxWsServiceFactoryBean" /> </jaxws:serviceFactory> <jaxws:features> <bean class="org.apache.cxf.feature.LoggingFeature" /> </jaxws:features> </jaxws:endpoint> 拦截器内容如下,主要就是从soap协议中获取head部分的节点,然后拿头的值做判断。 package tsb.ws.common.authentication; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.NodeList; public class cnm extends AbstractPhaseInterceptor<SoapMessage> { // 取得Log实例 private static Log log = LogFactory.getLog(ReadSoapHeader.class); private SAAJInInterceptor saa = new SAAJInInterceptor(); public cnm() { super(Phase.PRE_PROTOCOL); getAfter().add(SAAJInInterceptor.class.getName()); } @Override public void handleMessage(SoapMessage message) throws Fault { // 获取soap信息 SOAPMessage mess = message.getContent(SOAPMessage.class); if (mess == null) { saa.handleMessage(message); mess = message.getContent(SOAPMessage.class); } SOAPHeader head = null; try { head = mess.getSOAPHeader(); } catch (SOAPException e) { e.printStackTrace(); } if (head == null) { return; } try { // 读取soap头中的userid节点 NodeList nodes = head.getElementsByTagName("userid"); // 读取soap头中的userid节点 NodeList nodepass = head.getElementsByTagName("userpwd"); // 此处可加各种验证 } catch (Exception e) { SOAPException soapExc = new SOAPException("验证失败"); throw new Fault(soapExc); } } } **************************************************************************************************************************************************** 另外也记一下用wss4j的UsernameToken进行验证的配置,基本上和自定义soapheader也差不多同样是采用拦截器的方法 客户端配置文件的endpoint中添加如下拦截器,其中clientPasswordCallback用于指定添加验证信息的处理类; UsernameToken是指使用用户名令牌;PasswordText指密码加密策略,这里直接文本;xxx?指别名。
<bean id="TsbServiceFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean"> <property name="address" value="http://localhost:8080/TsbWebService/Cyf?wsdl"></property> <property name="serviceClass" value="tsb.ws.tsbinterface.ICyfClient"></property> <property name="outInterceptors"> <list> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="passwordType" value="PasswordText" /> <entry key="user" value="xxx" /> <entry key="passwordCallbackRef"> <ref bean="clientPasswordCallback" /> </entry> </map> </constructor-arg> </bean> </list> </property> </bean>添加验证信息 package cxf.client; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.ws.security.WSPasswordCallback; public class ClientPasswordCallback implements CallbackHandler { @Override public void handle(Callback[] callbacks) throws IOException,UnsupportedCallbackException { WSPasswordCallback ws = (WSPasswordCallback) callbacks[0]; ws.setPassword("xxxx"); ws.setIdentifier("xxxx"); } }服务端通过拦截器接收验证信息,serverPasswordCallback表示验证处理的类
<jaxws:endpoint id="TsbWebService" implementor="tsb.ws.tsbimpl.TsbWebServiceImpl" address="/Tsb"> <jaxws:inInterceptors> <!-- 日志拦截器 --> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> <!-- 自定义拦截器,用于实现认证操作 --> <bean class="tsb.ws.common.authentication.ReadSoapHeader" /> <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="passwordType" value="PasswordText" /> <entry key="user" value="xxx" /> <entry key="passwordCallbackRef"> <ref bean="serverPasswordCallback" /> </entry> </map> </constructor-arg> </bean> </jaxws:inInterceptors> <jaxws:serviceFactory> <ref bean="jaxWsServiceFactoryBean" /> </jaxws:serviceFactory> <jaxws:features> <bean class="org.apache.cxf.feature.LoggingFeature" /> </jaxws:features> </jaxws:endpoint> 服务端获取客户端发来的验证信息方法如下
WSPasswordCallback ws = (WSPasswordCallback) callbacks[0]; // 获取用户名 String identifier = ws.getIdentifier(); // 获取用户密码 ? String password = ws.getPassword(); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |