加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读