CXF发布WS,不用tomcat,实现usernametoken认证机制(1)

最近项目中用到了Web service,不愿意使用wsdl2java的方式,完全xml生成soap信封。

自己架设了WS服务及客户端测试,并实现了username token认证

java有三个WS规范,分别为JAXM&SAAJ、 JAX-WS (JAX-RPC)、 JAX-RS

本例属于JAX-WS

关于服务:使用Person类作为参数,将Person更改后返回给client。分别实现一个简单的WS及一个带username token验证的WS。

关于客户端:两种方式实现WS:Service.Mode.PAYLOAD及Service.Mode.MESSAGE。这两种方式都为发送纯粹xml机制,不用关注wsdl到javabean的转换。PAYLOAD只用关心soap的信封体(body),MESSAGE要实现soap信封(header and body),并且MESSAGE增加了username token认证。

准备工作:

1、到官网http://cxf.apache.org/,下载最新版本,我下载时最新为apache-cxf-2.2.9.zip,大概32M

2、解压,我打开了两个eclipse,分别建工程,一个为server一个为client,以便测试用,并分别引入cxf文件夹下的lib目录下的所有jar

下面是代码

服务器端:

定义一个WS接口

package test.service;
import javax.jws.WebService;

@WebService
public interface IHello {

Person getPerson(Person child);


}

编写一个实限类

package test.service;

public class Hello implements IHello {

public Person getPerson(Person child) {
   Person p=new Person();
   p.setAge(child.getAge()+20);
   p.setUserName(child.getUserName()+"'s father.");
   return p;
}

}

是不是缺少一个Person?那就创建吧

package test.service;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="PersonName")
public class Person {

private String userName=null;
private int age=0;
public String getUserName() {
   return userName;
}
public void setUserName(String userName) {
   this.userName = userName;
}
public int getAge() {
   return age;
}
public void setAge(int age) {
   this.age = age;
}

}

好了,完事具备,只欠启动了,写一个main类吧

package test.service;
import java.util.HashMap;
import java.util.Map;

import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
public class Server {

public static void main(String[] args) {
   Server server=new Server();
   server.test(); //简单的不带usernametoken的WS
   //server.testUserNameToken();// 启用usernametoken的WS
}
public void test(){
   EndpointImpl.publish("http://127.0.0.1:8888/helloServer", new Hello());
}
private WSS4JInInterceptor getInInterceptor(){
   Map<String,Object> inProps= new HashMap<String,Object>();
   inProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
   // 密码类型 : plain text
   inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
   // 客户信息校验类设置
   inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ServerPasswordCallback.class.getName());

   return new WSS4JInInterceptor(inProps);
}
private WSS4JOutInterceptor getOutInterceptor(){
   Map<String,Object> outProps = new HashMap<String,Object>();
   outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
   // 服务器用户标识
   outProps.put(WSHandlerConstants.USER, "IamServer");
   // 密码类型 : plain text
   outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
   // 返回给客户端的密码信息
   outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName());
   return new WSS4JOutInterceptor(outProps);
  
}

public void testUserNameToken(){
   EndpointImpl jaxWsEndpoint = (EndpointImpl) EndpointImpl.publish("http://127.0.0.1:8888/helloServer", new Hello());
   Endpoint cxfEndpoint = jaxWsEndpoint.getServer().getEndpoint();

   cxfEndpoint.getInInterceptors().add(getInInterceptor());
   //cxfEndpoint.getInInterceptors().add(new SAAJInInterceptor()); // 2.0.x 需要该句; 2.1及以上不需要

   cxfEndpoint.getOutInterceptors().add(getOutInterceptor());
   //cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor()); // 2.0.x 需要该句; 2.1及以上不需要

}
}

说明:上面过程创建了一个服务类,其实是两个服务,测试时在main方法里分别启用

另外用到两个身份验证的CallbackHandler ,分别实现如下

package test.service;

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 ServerPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
    UnsupportedCallbackException {

   WSPasswordCallback pwcb = (WSPasswordCallback) callbacks[0];
   String id = pwcb.getIdentifier();
   switch (pwcb.getUsage()) {
   case WSPasswordCallback.USERNAME_TOKEN_UNKNOWN:
    // 密码方式 plaintext
    if (!"leezuu".equals(id)) {
     throw new UnsupportedCallbackException(pwcb,
       "username is invalid.");
    }
    if (!"mima".equals(pwcb.getPassword())) {
     throw new UnsupportedCallbackException(pwcb,
       "password is invalid.");
    }
    break;

   case WSPasswordCallback.DECRYPT:
   case WSPasswordCallback.SIGNATURE:
    // used to retrieve password for private key
    if ("serverkey".equals(id)) {
     pwcb.setPassword("serverpass");
    }
    break;
   }

}
}

package test.service;

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 {

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

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        //服务器标识
        System.out.println("Server ID:"+pc.getIdentifier());
        // 设置返回给客户的服务器密码信息
        pc.setPassword("sssss");
    }

}

可能要问,WS不是运行在WEB容器里的吗?上面的 EndpointImpl.publish("http://127.0.0.1:8888/helloServer", new Hello());一句话就可以启动一个WS?

对的,WS需要容器,CXF下载的包中其实已经包括了一个,那就是Jetty,虽然没有tomcat,但其实还是有容器的。

ok,运行下,看到许多输出

打开IE,输入地址查看wsdl,http://127.0.0.1:8888/helloServer?wsdl

<?xml version="1.0" encoding="UTF-8" ?>
-  < wsdl:definitions name =" HelloService "  targetNamespace =" http://service.test/ "  xmlns:ns1 =" http://schemas.xmlsoap.org/soap/http "  xmlns:soap =" http://schemas.xmlsoap.org/wsdl/soap/ "  xmlns:tns =" http://service.test/ "  xmlns:wsdl =" http://schemas.xmlsoap.org/wsdl/ "  xmlns:xsd =" http://www.w3.org/2001/XMLSchema ">
-  < wsdl:types >
-  < xs:schema elementFormDefault =" unqualified "  targetNamespace =" http://service.test/ "  version =" 1.0 "  xmlns:tns =" http://service.test/ "  xmlns:xs =" http://www.w3.org/2001/XMLSchema ">
< xs:element  name =" PersonName "  type =" tns:person " />
< xs:element  name =" getPerson "  type =" tns:getPerson " />
< xs:element  name =" getPersonResponse "  type =" tns:getPersonResponse " />
-  < xs:complexType name =" getPerson ">
-  < xs:sequence >
< xs:element  minOccurs =" 0 "  name =" arg0 "  type =" tns:person " />
</ xs:sequence >
</ xs:complexType >
-  < xs:complexType name =" person ">
-  < xs:sequence >
< xs:element  name =" age "  type =" xs:int " />
< xs:element  minOccurs =" 0 "  name =" userName "  type =" xs:string " />
</ xs:sequence >
</ xs:complexType >
-  < xs:complexType name =" getPersonResponse ">
-  < xs:sequence >
< xs:element  minOccurs =" 0 "  name =" return "  type =" tns:person " />
</ xs:sequence >
</ xs:complexType >
</ xs:schema >
</ wsdl:types >
-  < wsdl:message name =" getPersonResponse ">
< wsdl:part  element =" tns:getPersonResponse "  name =" parameters " />
</ wsdl:message >
-  < wsdl:message name =" getPerson ">
< wsdl:part  element =" tns:getPerson "  name =" parameters " />
</ wsdl:message >
-  < wsdl:portType name =" IHello ">
-  < wsdl:operation name =" getPerson ">
< wsdl:input  message =" tns:getPerson "  name =" getPerson " />
< wsdl:output  message =" tns:getPersonResponse "  name =" getPersonResponse " />
</ wsdl:operation >
</ wsdl:portType >
-  < wsdl:binding name =" HelloServiceSoapBinding "  type =" tns:IHello ">
< soap:binding  style =" document "  transport =" http://schemas.xmlsoap.org/soap/http " />
-  < wsdl:operation name =" getPerson ">
< soap:operation  soapAction =""  style =" document " />
-  < wsdl:input name =" getPerson ">
< soap:body  use =" literal " />
</ wsdl:input >
-  < wsdl:output name =" getPersonResponse ">
< soap:body  use =" literal " />
</ wsdl:output >
</ wsdl:operation >
</ wsdl:binding >
-  < wsdl:service name =" HelloService ">
-  < wsdl:port binding =" tns:HelloServiceSoapBinding "  name =" HelloPort ">
< soap:address  location =" http://127.0.0.1:8888/helloServer " />
</ wsdl:port >
</ wsdl:service >
</ wsdl:definitions >

这样一个服务就已经发布了,可以根据需要实现相应的client,下面是一个实现,采用xml的方式,不用javabean。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值