`
mj4d
  • 浏览: 302546 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

CXF:构建安全的webservice服务

阅读更多

主要讲解两种方式:

1、基于WS-Security的安全认证

加入依赖:

<dependency>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-rt-ws-security</artifactId>
	<version>2.7.0</version>
</dependency>

可能会遇到的异常:encache时日志不能正确

java.lang.IllegalStateException: org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit
	org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:282)
	org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:248)
	org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:261)
	net.sf.ehcache.CacheManager.<clinit>(CacheManager.java:125)
	org.apache.cxf.ws.security.cache.EHCacheManagerHolder.getCacheManager(EHCacheManagerHolder.java:76)

 在cxf2.7.0中用的1.5.8报错修改版本:

<dependency>
	<groupId>org.slf4j</groupId>
	<artifactId>slf4j-api</artifactId>
	<version>1.6.1</version>
</dependency>

CXF对WS-Security的实现还是采用Interceptor的方式,我们在需要调用的地方构造WSS4JInInterceptor的实例。

1、server端配置:

<jaxws:server id="cxfSecurityService"
	serviceClass="org.ws.server.cxf.chap2.CXFSecurityService" address="/cxfSecurityService">
	<jaxws:serviceBean>
		<bean class="org.ws.server.cxf.chap2.impl.CXFSecurityServiceImpl" />
	</jaxws:serviceBean>
	<jaxws:inInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
		<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="admin" />
					<entry key="passwordCallbackRef">
						<ref bean="serverPasswordCallback" />
					</entry>
				</map>
			</constructor-arg>
		</bean>
	</jaxws:inInterceptors>
	<jaxws:outInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
	</jaxws:outInterceptors>
</jaxws:server>
<bean id="serverPasswordCallback" class="org.ws.server.cxf.chap2.interceptor.ServerAuthCallBack">
 <property name="username" value="admin" />
 <property name="password" value="admin123" />
</bean>

作为服务端,这里对传入参数加入了WSS4JInInterceptor,这里构造函数传入Map关注下这四个参数的含义:

 

 

  • action:UsernameToken 指使用用户名令牌   
  • passwordType: PasswordText采用UsernameToken的加密策略,默认为 WSConstants.PW_DIGEST,即PasswordDigest。这里直接文本
  • passwordCallbackRef:指定获取对象password的方式,需要实现CallbackHandler
这里构造函数中map的entry和key可见WSHandlerConstantsWSConstants

 

下面来看看passwordCallbackRef服务端的校验:

public class ServerAuthCallBack implements CallbackHandler {

    private String username;
    private String password;

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        String identifier = pc.getIdentifier();
        if (!StringUtils.isEmpty(getUsername()) && !StringUtils.isEmpty(getPassword())) {
            if (getUsername().equals(identifier)) {
                pc.setPassword(getPassword());
            }
        } else {
            throw new SecurityException("验证失败");
        }
    }

//getter/setter
}

对于CXF2.3.X(包括2.3.X)以下的版本在校验时需要这样:

public class ServerPasswordCallback implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException, 
        UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        if (pc.getIdentifer().equals("joe") {
           if (!pc.getPassword().equals("password")) {
                throw new IOException("wrong password");
           }
        }
    }

}

更多信息见这里

 

2、客户端校验

与服务端类似,需要在配置文件的outinterceptors加入

<jaxws:client id="cxfSecurityClient"
	address="http://localhost:8080/webservice/service/cxfSecurityService"
	serviceClass="org.sample.ws.client.cxf.chap3.CXFSecurityService">
	<jaxws:inInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
	</jaxws:inInterceptors>
	<jaxws:outInterceptors>
		<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="admin" />
					<entry key="passwordCallbackRef">
						<ref bean="clientPasswordCallback" />
					</entry>
				</map>
			</constructor-arg>
		</bean>
	</jaxws:outInterceptors>
</jaxws:client>

 而客户端只需要将注入的username和password设置到相应的属性即可:

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback wsPasswordCallBack = (WSPasswordCallback) callbacks[0];
        wsPasswordCallBack.setIdentifier(getUsername());
        wsPasswordCallBack.setPassword(getPassword());
    }

 

 

2、Intercepter

另一种思路,之前在介绍JAX-WS的时候提供了一种思路,在SOAP的head中添加QName节点,加入用户信息这里同样也可以采用这样的方式来实现:

public class SecuritySOAPHeaderIntercepter extends AbstractSoapInterceptor {

    private String qName;
    private String key;
    private String token;
    private String tokenValue;

    public SecuritySOAPHeaderIntercepter() {
        super(Phase.WRITE);
    }

    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headers = message.getHeaders();
        headers.add(getHeader());
    }

    private Header getHeader() {
        QName qName = new QName(getqName(), getKey());
        Document document = DOMUtils.createDocument();
        Element element = document.createElementNS(getqName(), getKey());
        Element token = document.createElement(getToken());
        token.setTextContent(getTokenValue());
        element.appendChild(token);
        SoapHeader header = new SoapHeader(qName, element);
        return (header);
    }

//getter/setter
}

对上面的代码我们需要关注两点:

1、指定该拦截器的执行阶段,需要在构造函数中指定,这里是写入阶段Phase.WRITE

2、实现自定义的拦截器主要需要实现handleMessage,这里是在SOAP的header中加入qname为节点的元素,具体生产的格式如下:

 

<soap:Header><user_admin xmlns="http://org.webservice.cxf.sample"><user_token>1234567</user_token></user_admin></soap:Header>

当然,在实际的业务中可自行构造该节点格式。所需要注意的就是在server端按照该节点来解析获取相应的值来判断即可。如针对上述生成的header文件,我们可以通过解析user_admin,namespace,user_token,value等值来作为校验的依据

对客户端配置,只需要将该拦截器作为输出拦截器链中

 

<!-- 基于SOAPinterceptor -->
<jaxws:client id="cxfHeaderSecurityClient"
	address="http://localhost:8080/webservice/service/cxfHeaderSecurityService"
	serviceClass="org.sample.ws.client.cxf.chap4.CXFSecurityService">
	<jaxws:inInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
	</jaxws:inInterceptors>
	<jaxws:outInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
		<bean
			class="org.sample.ws.client.cxf.chap4.interceptor.SecuritySOAPHeaderIntercepter">
			<property name="qName" value="http://org.webservice.cxf.sample" />
			<property name="key" value="user_admin" />
			<property name="token" value="user_token" />
			<property name="tokenValue" value="1234567" />
		</bean>
	</jaxws:outInterceptors>
</jaxws:client>

 接下来看看服务端配置,根据上述的SOAP协议header部分,我们需要做的就是解析该header获取相应的值作为检验的依据:

 

public class SecuritySOAPHeaderIntercepter extends AbstractSoapInterceptor {

    private static final Logger LOG = Logger.getLogger(SecuritySOAPHeaderIntercepter.class.getName());

    private String              qName;
    private String              key;
    private String              token;
    private String              tokenValue;

    public SecuritySOAPHeaderIntercepter() {
        super(Phase.PRE_LOGICAL);//这里指定在拦截器链中的执行阶段为PRE_PROTOCOL
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        List<Header> headers = message.getHeaders();
        boolean authorized = false;
        if (null != headers && !headers.isEmpty()) {
            for (Header header : headers) {
                QName qName = header.getName();
                if (getKey().equals(qName.getLocalPart()) && getqName().equals(qName.getNamespaceURI())) {
                    Element element = (Element) header.getObject();
                    NodeList nodeList = element.getChildNodes();
                    for (int i = 0; i < nodeList.getLength(); i++) {
                        Node node = nodeList.item(i);
                        if (getToken().equals(node.getNodeName())
                                && getTokenValue().equals(node.getFirstChild().getNodeValue())) {
                            authorized = true;
                            break;
                        }
                    }
                }
            }
        }

        if (!authorized) {
            throw new Fault("authorized error", LOG);
        }
    }

    //getter/setter

}

在handleMessage方法中通过解析SOAP中header来达到授权的目的。

指定了在拦截器链中的执行阶段,这里是Phase.PRE_PROTOCOL。更多的执行阶段见下面:

或者这里http://cxf.apache.org/docs/interceptors.html

接下来将上述的拦截器设置为传入的拦截器链:
<!-- 采用soapHeader的方式 -->
<jaxws:server id="cxfHeaderSecurityService"
	serviceClass="org.ws.server.cxf.chap2.CXFSecurityService" address="/cxfHeaderSecurityService">
	<jaxws:serviceBean>
		<bean class="org.ws.server.cxf.chap2.impl.CXFSecurityServiceImpl" />
	</jaxws:serviceBean>
	<jaxws:inInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
		<bean class="org.ws.server.cxf.chap2.interceptor.AnotherInterceptor"/>
		<bean
			class="org.ws.server.cxf.chap2.interceptor.SecuritySOAPHeaderIntercepter">
			<property name="qName" value="http://org.webservice.cxf.sample" />
			<property name="key" value="user_admin" />
			<property name="token" value="user_token" />
			<property name="tokenValue" value="123456" />
		</bean>
	</jaxws:inInterceptors>
	<jaxws:outInterceptors>
		<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
	</jaxws:outInterceptors>
</jaxws:server>
 

 

 

分享到:
评论

相关推荐

    简单cxf+spring构建webservice服务

    标题“简单cxf+spring构建webservice服务”指的是使用Apache CXF框架与Spring框架结合来创建Web服务。Apache CXF是一个开源的Java框架,它允许开发者创建和消费各种Web服务,包括SOAP和RESTful风格。Spring框架则为...

    使用Eclipse+Maven+Spring+CXF构建的WebService服务

    Web项目中基于Maven与Spring整合的WebService之cxf的实现⬇️ 详情请参考如下链接: https://locqi.github.io/locqi.com/2018/09/05/Eclipse+Maven+Spring+CXF-create-WebService/

    CXF 一个完整的webService(整合客户端和服务端)

    【CXF:构建Web服务的全面指南】 CXF(CXF: XFire Community eXtended)是一个开源的Java框架,用于构建和部署Web服务。它提供了强大的支持,包括SOAP、RESTful API、WS-*规范等多种协议和服务模型。CXF不仅简化了...

    apache-cxf-3.0.16.zip_cxf index:0_webservice

    "cxf index:0"可能是指在某个索引系统或资源库中,CXF组件的特定位置,而"Webservice"标签则明确了该压缩包与Web服务紧密相关。 Apache CXF的核心功能包括: 1. **SOAP支持**:CXF 支持SOAP 1.1和1.2协议,允许...

    基于SSM+CXF构建的RESTFul webservice

    使用cxf、spring构建的rest风格webservice,其他相关技术springmvc、mybatis、druid等。代码中使用的数据库为sybase,请根据实际环境更改,需修改pom中引用的数据库驱动,依照entity类的属性建对应表,并修改config....

    webService(基于cxf)的完整例子

    CXF是一个流行的开源Java框架,用于构建和消费Web服务。它提供了丰富的功能,包括SOAP、RESTful API支持以及多种协议和标准的实现。在这个基于CXF的Web服务完整例子中,我们将深入探讨CXF的核心概念、配置、以及如何...

    cxf+spring实现webservice

    CXF允许开发者以Java编程方式或者基于XML的WSDL(Web Services Description Language)文件来构建Web服务。Spring框架则是一个广泛使用的Java企业级应用框架,提供了依赖注入、AOP(面向切面编程)、数据访问和事务...

    CXF实现简单的WebService接口开发

    此外,CXF还支持各种高级特性,如WS-Security(Web服务安全)、WS-Policy(Web服务策略)等,以及与其他Java EE组件(如JMS、JPA)的集成。这使得CXF成为企业级Web服务开发的强大工具。 通过阅读相关的博客和实践...

    CXF框架发布webservice

    学习这些内容后,开发者将能够熟练地使用CXF框架和Spring框架来构建和发布高质量的Web服务,同时也能掌握服务的测试、安全性和事务管理等关键环节。通过实践,你可以更好地理解和掌握这些技术,提升你的Web服务开发...

    CXF和Spring搭建webservice代码

    在Java开发领域,CXF和Spring框架的结合是构建高效、灵活的Web服务的常见选择。CXF是一个开源的SOAP和RESTful Web服务框架,它允许开发者轻松地创建和消费Web服务。而Spring框架则是Java企业级应用的基石,提供了一...

    cxf+spring发布webservice和restservice

    Apache CXF是一个开源的、功能丰富的服务栈,它使得开发者能够轻松地构建和部署SOAP和RESTful Web服务。 首先,让我们深入理解SOAP Web服务。SOAP是一种XML格式的协议,用于在Web上交换结构化的和类型化的信息。...

    Spring+CXF 发布WebService服务

    Apache CXF,另一方面,是一个开源的服务框架,主要用于构建和部署SOAP和RESTful Web服务。CXF支持多种Web服务规范,如WS-I Basic Profile、WS-Security等,让开发者能够创建符合标准的服务。 结合Spring和CXF,...

    基于CXF的webservice的发布及访问

    在Java开发中,Apache CXF是一个广泛使用的开源框架,用于构建和实现Web服务。本教程将详细介绍如何利用CXF发布基于SOAP 1.2的Web服务,以及如何进行客户端调用。首先,我们需要理解Web服务的基本概念。 Web服务是...

    CXF V3.2.4 实现的WebService调用(带安全认证)

    在本文中,我们将深入探讨...总之,Apache CXF V3.2.4提供了一套强大且灵活的工具,帮助开发者构建和消费具有安全认证的Web服务。通过理解这些基本步骤和安全概念,你可以有效地保护你的Web服务免受未经授权的访问。

    13.为CXF与Spring整合发布WebService添加拦截器进行权限控制

    在IT行业中,Web服务是应用程序之间进行通信的一种标准方法,而CXF是一个流行的开源框架,用于构建和消费Web服务。Spring框架则是一个广泛使用的Java企业级应用开发框架,提供了丰富的功能,包括依赖注入、AOP(面向...

    CXF3.0.9+SPRING开发webservice例子

    CXF(CXF: Apache CXF)是一个开源的Java框架,专为构建和部署Web服务而设计。Spring框架则是Java企业级应用开发的事实标准,提供了一个全面的编程和配置模型,使得开发、测试和集成复杂的应用变得简单。当我们谈论...

    使用CXF和camel-cxf调用webservice

    CXF提供了丰富的API和工具,使得开发者可以快速构建服务提供者和服务消费者。同时,CXF也集成了多种传输协议,如HTTP、JMS和JBI,增强了其灵活性和可扩展性。 在使用CXF调用Web服务时,通常会经历以下步骤: 1. **...

    cxf与spring发布WebService

    CXF(CXF:CXF Extends Fuses)是一个开源的服务栈,主要用于构建和服务导向架构(SOA),它支持多种Web服务标准,如SOAP、WS-Security等。Spring则是一个广泛应用的轻量级Java应用框架,提供强大的依赖注入和AOP...

    CXF+Jetty发布WebService

    CXF(CXF: The Apache CXF project)是一个开源的Java框架,专门用于构建和部署Web服务。Jetty则是一款轻量级的HTTP服务器和Servlet容器,它常被用于嵌入式场景,如开发简单的Web应用或者作为Web服务的运行环境。本...

    Java cxf开发webservice,分别有客户端和服务端

    2.用cxf开发webservice 3.这个服务端和客户端的小demo 在服务端 对外开放接口服务,然后在客户端 调用服务端的方法, 实现客户端(一个javaweb项目)对服务端(javaweb项目)方法的调用, 实际上就是发送和接收消息...

Global site tag (gtag.js) - Google Analytics