`
StupidBirds
  • 浏览: 8121 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

Cxf Webservice安全认证

 
阅读更多

 在开发的时候发布webservice,为了安全通常需要安全验证,在CXF中的实现,在这里记录一下。

 

CXF是啥 我就不介绍了, 开发CXF+Spring的webservice服务:

 

 在这里发布一个简单的服务,比如发布的服务为SpingService

 

 写道
这里只是一个简单的接口,通过注解标注这是一个WebService接口:

import javax.jws.WebService;

@WebService
public interface SpringService {
String play(String info);
}

 

 

 

具体的实现类:

    写道

通过WebService注解中的endpointInterface指到刚才我定义的那个接口,发布出来的服务将会就是那个接口的样子:

import javax.jws.WebService;

@WebService(endpointInterface="cn.jd.ws.SpringService")
public class DotaSpringService implements SpringService{

public String play(String info) {
System.out.println("play called!");
return "Dota [ " + info + " ]";
}

}
 

 Spring中的配置:

  写道

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
">
需要插入jaxws这个库
 

 

 写道

在spring的配置文件中导入cxf包下的文件:
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>

 

 

在spring中发布服务:

 

 写道
把我们刚才实现的服务发布出来:
<jaxws:endpoint id="dotaService" implementor="cn.jd.ws.DotaSpringService" address="/DotaService">
<jaxws:inInterceptors>
<ref bean="soapAuth"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
参数implementor指定这个发布出来的WebService服务的实现类是哪个,address表示访问的地址,其中的拦截器就是我们需要将的那个安全验证的拦截器。稍后会介绍到。
<bean  id="soapAuth" class="cn.jd.ws.interceptor.SOAPAuthIntercepter"><property name="token" value="ssssdddd"></property></bean>
这里配置了一个令牌,当然为了安全最好是通过MD5等安全加密算法加密过的。为了简单直接搞了一个。

可能通过代码提示功能的我们都发现了还有一个发布服务的标签:

<jaxws:server id="" serviceClass="cn.jd.ws.DotaSpringService" address="/DataService">
<jaxws:inInterceptors>
<ref bean="soapAuth"/>
</jaxws:inInterceptors>
</jaxws:server>

那么endpoint和server这两种方式有啥区别?

 

 

 其实这两种方式就是刚学习发布第一个Webservice时可能编写的那两种方式的替换。

 

 写道
比如我们不通过Spring来简单发布一个Webservie,我们会这么做:
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService
public interface HiService {
//to make sure the paramter is named correctly in the xml
String sayHi(@WebParam(name="text") String text);
}

实现:
import javax.jws.WebService;
import javax.xml.ws.Endpoint;

import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
/**
* A simple JAX-WS 规范的XML web services的JAVA API
*/
@WebService(endpointInterface="cn.jd.ws.HiService",serviceName="HiService")
public class HiServiceImpl implements HiService{

public static final String ENDPOINT = "http://localhost:9090/HiSerivice";

@Override
public String sayHi(String text) {
return "Hi " + text;
}

//这种方式就相当于是jaxws:endpoint
public void startServer() {
System.out.println("Starting the server");
HiServiceImpl hiService = new HiServiceImpl();
//通过Endpoint的方式直接就发布了
Endpoint.publish(ENDPOINT, hiService);
}

//这种方式就是jaxws:service方式
public void startServerNormal() {
      //这里利用的就是JaxWsServerFactoryBean
     JaxWsServerFactoryBean serverFactoryBean = new JaxWsServerFactoryBean();
     HiServiceImpl hiService = new HiServiceImpl();
    //服务类接口
    serverFactoryBean.setServiceClass(HiService.class);
   //设置地址
  serverFactoryBean.setAddress(ENDPOINT);
  serverFactoryBean.setServiceBean(hiService);
  serverFactoryBean.getInInterceptors().add(new LoggingInInterceptor());
  serverFactoryBean.create();
}

//发布服务
public static void main(String[] args) {
try {
  //能通过浏览器看到 是因为cxf自带了一个jetty服务器
  new HiServiceImpl().startServerNormal();
  System.out.println("发布服务成功");
}catch (Exception e) {
  System.out.println("发布服务失败");
}
}
}
 

 

然后就是配置CXFServlet的自启动:

 

 写道
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value></context-param>


<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/soap/*</url-pattern>
</servlet-mapping>

 

 

这些都是简单的配置,接下来就该编写我们的安全验证类了:

 

其实理解安全机制实现的原理很简单:

 

   就是客户端的每一次请求,都要带着请求头,而服务端就去解析请求头,看里面带的token是否跟预期的一致,如果一致就说明安全了,

否则就抛出异常不让调用。

 

   那么就有两个操作:

1.在客户端发送webservice调用以前,构造一个SOAP消息头,把token带过去

2.在服务端解析消息头,把指定的那个头字段解析出来,对比 两边的token是否相同

 

 

 

 

首先是服务器端:

 

   写道

public class SOAPAuthIntercepter extends AbstractPhaseInterceptor<SoapMessage>{

private SAAJInInterceptor saaIn = new SAAJInInterceptor();

private String namespaceURI = "http://test.com/auth";

private String localPart = "MyAuthHeader";

public SOAPAuthIntercepter() {
//在哪个阶段被拦截
super(Phase.PRE_PROTOCOL);
getAfter().add(SAAJInInterceptor.class.getName());
}

public void handleMessage(SoapMessage message) throws Fault {
System.out.println("=========>message:" + message);
if( !checkQnameHeader(message) && !checkMessageHeader(message)) {
throw new IllegalArgumentException("The Token wrong!");
}
}


**
* 校验指定的Qname头
* @param message
* @return
*/
private boolean checkQnameHeader(SoapMessage message) {
SoapHeader header = (SoapHeader)message.getHeader(new QName(namespaceURI, localPart));
if(header == null) {
return false;
}
ElementNSImpl ei = (ElementNSImpl) header.getObject();
String mytoken;
try {
mytoken = ei.getFirstChild().getFirstChild().getTextContent();
return mytoken.equals(token);
} catch (Exception e) {
throw new IllegalArgumentException("Method --> checkQnameHeader error",e);
}
}

/**
* 校验消息头
* @param message
* @return
*/
private boolean checkMessageHeader(SoapMessage message) {
try {
SOAPMessage mess = message.getContent(SOAPMessage.class);
if(mess == null) {
saaIn.handleFault(message);
mess = message.getContent(SOAPMessage.class);
}
//获得SOAPHeader
SOAPHeader head = mess.getSOAPHeader();
if(head == null) return false;

//获得这个名称的NodeList
NodeList nodes = head.getElementsByTagName(localPart);
if(nodes == null) return false;

//取出来判断是否相等
String mytoken = "";
for (int i = 0; i < nodes.getLength(); i++) {
mytoken += nodes.item(i).getTextContent();
}

return mytoken.equals(token);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}

}
 

 

再就是客户端:

  写道




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.helpers.DOMUtils;
import org.apache.cxf.helpers.XMLUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class JdAuthOutInterceptor extends AbstractSoapInterceptor{

private AuthHeader authHeader;

public JdAuthOutInterceptor() {
super(Phase.WRITE); //在写之前
}

public void handleMessage(SoapMessage message) throws Fault {
//设定一个QName 这里的key就是localPart uri就是自定义的
QName qname = new QName(authHeader.getqName(), authHeader.getKey());
//构造一个XML
Document doc = DOMUtils.createDocument();

//创建给定的限定名称和名称空间 URI 的元素 这些操作都是jdk中的代码
Element authElement = doc.createElementNS(authHeader.getqName(),authHeader.getKey());
Element tokenElement = doc.createElement(authHeader.getToken());//令牌
tokenElement.setTextContent(authHeader.getTokenValue()); //设置值为
authElement.appendChild(tokenElement);


XMLUtils.printDOM(authElement);
//SOAP头 将有authElement元素组成
SoapHeader header = new SoapHeader(qname, authElement);
//把我们构造的这个头 添加到message中去
message.getHeaders().add(header);
}

public void setAuthHeader(AuthHeader authHeader) {
this.authHeader = authHeader;
}
}

 

构造一个SoapHeader对象:

 

  写道

import org.apache.commons.lang.StringUtils;

public class AuthHeader {

private final static String QNAME = "http://test.com/auth";
private String KEY = "MyAuthHeader";
private String TOKEN = "Token";

private String qName;
private String key;
private String token;
private String content;

public AuthHeader() {}

public String getqName() {
if(StringUtils.isEmpty(qName))
qName = QNAME;
return qName;
}

public void setqName(String qName) {
this.qName = qName;
}

public String getKey() {
if(StringUtils.isEmpty(key))
key = KEY;
return key;
}

public void setKey(String key) {
this.key = key;
}

public String getTokenValue() {
//令牌值
return content;
}

public String getToken() {
if(StringUtils.isEmpty(token)) {
token = TOKEN;
}
return token;
}

public void setToken(String token) {
this.token = token;
}

public void setContent(String content) {
this.content = content;
}
}

 

 

在Spring中配置一个客户端 ,启动服务后调用一下:

 

    写道

<bean id="mySoapAuth" class="cn.jd.ws.interceptor.JdAuthOutInterceptor">
<property name="authHeader" ref="authHeader"/>
</bean>

<!-- 客户端调用 -->
<jaxws:client id="dotaServiceClient" serviceClass="cn.jd.ws.SpringService" address="http://localhost:8080/Test/soap/DotaService">
<!-- 客户端outInterceptor 服务器端inInterceptor -->
<jaxws:outInterceptors>
<ref bean="mySoapAuth"/>
</jaxws:outInterceptors>
</jaxws:client>
 

 

 

 写道
public class SpringClientTest {

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
SpringService service = (SpringService)context.getBean("dotaServiceClient");
System.out.println(service.play(" 5人黑 呵呵!"));
}
}

 

 

运行后客户端输出结果:

  写道

<?xml version="1.0" encoding="utf-8"?><MyAuthHeader xmlns="http://test.com/auth"><Token>ssssdddd</Token></MyAuthHeader>
Dota [ 5人黑 呵呵! ]

 

 

分享到:
评论
4 楼 ljm653467 2013-10-09  
照着敲了一遍,还是有问题,没有密码webservice还是可以被人访问,求项目源码,先谢了    653467080@qq.com
3 楼 liuInsect 2012-11-06  
token怎么来的? 源码里面没有找到
2 楼 StupidBirds 2012-09-20  
yandong 写道
客户端中的配置

<bean id="mySoapAuth" class="cn.jd.ws.interceptor.JdAuthOutInterceptor">
<property name="authHeader" ref="authHeader"/>
</bean>


ref="authHeader"

这个authHeader是哪来的?


上面不是有一个AuthHeader这个类么

     <!-- 验证头 -->
     <bean id="authHeader" class="AuthHeader">
     <property name="content" value="ssssdddd"/>
     </bean>

类似这样子 配置下
1 楼 yandong 2012-09-20  
客户端中的配置

<bean id="mySoapAuth" class="cn.jd.ws.interceptor.JdAuthOutInterceptor">
<property name="authHeader" ref="authHeader"/>
</bean>


ref="authHeader"

这个authHeader是哪来的?

相关推荐

    cxf入门例子(安全认证)

    【CXF入门例子(安全认证)】 Apache CXF 是一个开源的 Java 框架,主要用于构建和开发服务导向架构(SOA)和 RESTful Web 服务。它提供了丰富的功能,包括SOAP、REST、WS-* 标准支持、数据绑定、JAX-RS 和 JAX-WS ...

    webService(基于cxf)的完整例子

    8. **安全与认证**:CXF支持多种安全机制,包括基本认证、digest认证、WS-Security等,确保Web服务的安全性。开发者可以根据需要添加相应的安全配置。 9. **错误处理与日志**:CXF提供了详细的错误处理机制和日志...

    使用cxf的webservice安全验证

    Apache CXF支持多种安全模型,包括基本认证、digest认证、WS-Security(如WS-SecurityPolicy、WS-Trust等)以及OAuth等。 标题“使用CXF的Web服务安全验证”提示我们关注的重点是通过CXF实现Web服务的安全配置。CXF...

    CXF webservice 示例工程(集成spring)

    综上所述,这个CXF Webservice示例工程涵盖了Spring集成、Web服务安全、大文件传输优化以及不同类型数据的处理,是学习和实践CXF框架的理想起点。通过对这些知识点的深入理解和实践,开发者能够更好地掌握如何在实际...

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

    在本文中,我们将深入探讨如何使用Apache CXF V3.2.4实现带有安全认证的Web服务调用。Apache CXF是一个开源框架,它允许开发者创建和消费各种Web服务,包括SOAP和RESTful API。CXF 3.2版本引入了许多增强功能,包括...

    CXF WebService带有拦截器

    总结起来,"CXF WebService带有拦截器"的实践是Web服务开发中的一个重要方面,它允许我们在不侵入核心业务逻辑的情况下,增加诸如权限控制这样的安全特性。通过"AuthFilter_Service"和"AuthFilter_Client",我们可以...

    java cxf webservice接口解决跨域问题

    Java CXF Webservice接口在处理Web服务时,可能会遇到跨域问题,这通常是由于浏览器的安全策略限制了不同源之间的通信。解决这个问题的关键在于理解和应用CORS(Cross-Origin Resource Sharing)机制。CORS允许...

    cxf webservice所需jar包

    - CXF提供了多种安全模型,包括基本认证、证书认证、WS-Security等,确保Web服务的安全通信。 9. **拦截器和 phases**: - CXF使用拦截器模型,允许在请求和响应的过程中插入自定义逻辑。这些拦截器可以用于日志...

    spring-cxf WebService

    1. 安全性:可以通过Spring的安全模块或CXF的扩展来添加认证和授权机制,如基本认证、令牌认证或SSL/TLS加密。 2. 异常处理:定义全局异常处理器,统一处理服务调用过程中的异常,提高服务的健壮性。 3. 性能优化:...

    使用CXF和camel-cxf调用webservice

    2. **配置服务客户端**:通过CXF的客户端API,你可以设置服务地址、认证信息等参数。这通常在Spring配置文件或代码中完成。 3. **调用服务**:一旦客户端准备好,就可以通过CXF客户端API来调用服务方法,传递必要的...

    CXF 2.4 WebService 发布和调用的身份验证和获取示例代码

    1. 发布和调用WebService: 使用CXF2.4(http://cxf.apache.org)和spring 2. 调用安全性: 使用简单的USERNAME_TOKEN 3. 服务程序中取得调用者身份 ------------------------- 接口 ------------------------- intf....

    纯java调用ws-security+CXF实现的webservice安全接口

    2. **创建安全上下文**:为了实现身份验证,你需要创建一个`WSS4JOutInterceptor`,并提供安全相关的配置,比如使用`UsernameToken`进行基本认证。这可以通过`WSSecurityProperties`类来完成。 3. **添加拦截器**:...

    cxf WebService

    9. **安全配置**:CXF支持各种安全模型,包括基本认证、数字签名、消息加密等。在实际项目中,需要根据业务需求设置合适的安全策略,防止未授权访问和数据泄露。 10. **持续学习与进阶**:理解并熟练掌握CXF ...

    CXF发布WebService加入拦截器

    当我们谈论"CXF发布WebService加入拦截器"时,这涉及到在CXF服务端和客户端增加拦截器来增强服务功能和控制流程。拦截器是CXF框架中的一个重要组件,它们提供了在消息发送和接收过程中插入自定义逻辑的能力。 一、...

    JAVA CXF webservice的示例代码

    Java CXF 是一个开源的Java框架,主要用于构建和开发Web服务。...在实际项目中,你可能需要处理更多的细节,比如错误处理、安全认证、性能优化等,但这个基础示例已经为你打开了Web服务开发的大门。

    cxf webService客户端

    CXF提供了丰富的API和插件支持,如MTOM(Message Transmission Optimization Mechanism)用于优化大附件传输,或者WS-Security用于安全认证。 此外,CXF还支持RESTful Web服务。对于RESTful服务,我们可以使用`...

    cxf webservice开发实例

    除了基本的配置,还有许多高级特性可以探索,如服务版本控制、安全认证、数据绑定、拦截器等。例如,通过添加安全配置,我们可以实现基于用户名和密码的身份验证,或者利用SSL进行加密传输。数据绑定则允许我们将XML...

    cxf webservice例子

    6. **安全性**:CXF提供了多种安全机制,如基本认证、OAuth、SSL/TLS等,以保护Web服务的安全性。你可以根据需求选择合适的策略来实施服务端和客户端的安全控制。 7. **测试工具**:CXF提供了内置的测试工具,如CXF...

    cxf webservice restful实现

    - 使用CXF的WS-Security功能,可以实现安全验证,如OAuth、基本认证等。 - 利用CXF的测试工具,如CXFTestSupport,可以方便地进行服务端和客户端的集成测试。 - 使用Postman等工具,可以模拟客户端对服务端的HTTP...

Global site tag (gtag.js) - Google Analytics