当前位置: 首页 > 工具软件 > WSS4J > 使用案例 >

CXF 集成wss4j

赵智
2023-12-01

项目需求对webservice接口进行加密,然后网上看到wss4j,于是翻阅资料写的歌DEMO

首先JAR包引入

        <!-- CXF 3.2.4   START-->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.2.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-ws-security</artifactId>
            <version>3.2.6</version>
        </dependency>

然后服务端CXF的配置类

import com.aadata.datacenter.dataManage.webservice.MessagePackService;
import org.apache.cxf.Bus;
import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.xml.ws.Endpoint;
import java.util.HashMap;
import java.util.Map;


@Configuration
public class CxfConfig {

	@Autowired
	private MessagePackService messagePackService;


	// 注意:要修改ServletRegistrationBean的别名,如果不修改会和前端控制器的Servlet名称冲突,导致spring找不到相应的servlet
	@Bean(name="CXFServlet")
	public ServletRegistrationBean dispatcherServlet() {
		return new ServletRegistrationBean(new CXFServlet(), "/webservice/*");// 发布服务名称 localhost:8080/webservice

	}

	@Bean(name = Bus.DEFAULT_BUS_ID)
	public SpringBus springBus() {
		return new SpringBus();
	}


	@Bean
	public Endpoint getDataManageServer() {
		EndpointImpl endpoint = new EndpointImpl(springBus(), messagePackService);
		Map<String, Object> inProps = new HashMap<String, Object>();
		inProps.put(WSHandlerConstants.USER, "admin");
		inProps.put(WSHandlerConstants.ACTION,WSHandlerConstants.USERNAME_TOKEN);//加密类型
		inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST); //密码类型为加密
		inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
				ExampleServiceInterceptor.class.getName());  //密码回调函数
		endpoint.getInInterceptors().add( new SAAJInInterceptor());
		endpoint.getInInterceptors().add(new WSS4JInInterceptor(inProps));
		endpoint.publish("/CommonService");
		return endpoint;
	}

}

服务端的拦截器


import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
import javax.security.auth.callback.CallbackHandler;

public class ExampleServiceInterceptor  implements CallbackHandler {

    private Map<String, String> passwords = new HashMap<String, String>();

    public ExampleServiceInterceptor() {
        passwords.put("admin1", "password1");//验证信息:用户名+密码,必须与客户端一致才可验证通过
    }
    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {

        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
            String identifier = pc.getIdentifier();//用户名
            int usage = pc.getUsage();//验证方式
            if (usage == WSPasswordCallback.USERNAME_TOKEN) {
                // 密钥方式USERNAME_TOKEN
                pc.setPassword(passwords.get(identifier));
            }else if (usage == WSPasswordCallback.SIGNATURE) {
                // 密钥方式SIGNATURE
                pc.setPassword(passwords.get(identifier));
 
            }
        }
    }

}

客户端拦截器


import org.apache.wss4j.common.ext.WSPasswordCallback;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;


public class ExampleServiceClientInterceptor implements CallbackHandler {

    private Map<String, String> passwords = new HashMap<String, String>();

    public ExampleServiceClientInterceptor() {
        passwords.put("admin1", "password1");
    }
    public void handle(Callback[] callbacks) {

        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
            String identifier = pc.getIdentifier();
            int usage = pc.getUsage();

            if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN
               
                pc.setPassword(passwords.get(identifier));/
            }else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE
                pc.setPassword(passwords.get(identifier));
            }
        }
    }
}

客户端调用主方法

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;


public class test020 {

    public static void main(String[] args) throws Exception {
        JaxWsDynamicClientFactory dcflient=JaxWsDynamicClientFactory.newInstance();

        Client client=dcflient.createClient("http://localhost:8999/webservice/CommonService?wsdl");
   

        Map<String, Object> outProps = new HashMap<String, Object>();
        outProps.put(WSHandlerConstants.ACTION,
                WSHandlerConstants.USERNAME_TOKEN);
        outProps.put(WSHandlerConstants.USER, "admin1");
        outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
        // 指定在调用远程ws之前触发的回调函数WsClinetAuthHandler,其实类似于一个拦截器
        outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
                ExampleServiceClientInterceptor.class.getName());
        ArrayList list = new ArrayList();
        // 添加cxf安全验证拦截器,必须
        list.add(new SAAJOutInterceptor());
        list.add(new WSS4JOutInterceptor(outProps));
        client.getOutInterceptors().addAll(list);
        QName name=new QName("http://webservice.dataManage.datacenter.aadata.com/","sayHello");
        Object[] objects=client.invoke(name,"wss4j+cxf实现WS-Security");
        System.out.println(objects[0].toString());

    }
}

 

 

CXF方式生成客户端调用 

CXF 客户端生成client对象命令:

C:\Users\Administrator\Downloads\apache-cxf-3.2.6\bin> wsdl2java -p com.aadata -d  C:\Users\Administrator\Desktop\test -client http://192.168.2.20:8088/WSSSS/webservice/CommonService/sayHello?wsdl 

对应的客户端拦截器

import org.apache.wss4j.common.ext.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import java.util.HashMap;
import java.util.Map;


public class ExampleServiceClientInterceptor implements CallbackHandler {

    private Map<String, String> passwords = new HashMap<String, String>();

    public ExampleServiceClientInterceptor() {
        passwords.put("HuQiuTest", "Ceshi_123456");
    }
    public void handle(Callback[] callbacks) {

        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
            String identifier = pc.getIdentifier();
            int usage = pc.getUsage();

            if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN
                System.out.println(passwords.containsKey(identifier)+"="+passwords.get(identifier)+"-"+identifier);
                pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
            }else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE
                pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
            }
        }
    }
}

对应客户端类(WSHandlerConstants.ACTION值有所修改,对应服务端也要修改):


package wsss;

/**
 * Please modify this class to meet your needs
 * This class is not complete
 */

import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

/**
 * This class was generated by Apache CXF 3.2.6
 * 2021-01-22T15:14:43.233+08:00
 * Generated source version: 3.2.6
 *
 */
public final class MessagePackService_MessagePackServiceImplPort_Client {

    private static final QName SERVICE_NAME = new QName("http://webservice.dataManage.datacenter.aadata.com/", "MessagePackService");

    private MessagePackService_MessagePackServiceImplPort_Client() {
    }

    public static void main(String args[]) throws Exception {
        URL wsdlURL = wsss.MessagePackService_Service.WSDL_LOCATION;
        if (args.length > 0 && args[0] != null && !"".equals(args[0])) {
            File wsdlFile = new File(args[0]);
            try {
                if (wsdlFile.exists()) {
                    wsdlURL = wsdlFile.toURI().toURL();
                } else {
                    wsdlURL = new URL(args[0]);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }

        wsss.MessagePackService_Service ss = new wsss.MessagePackService_Service(wsdlURL, SERVICE_NAME);
        wsss.MessagePackService port = ss.getMessagePackServiceImplPort();
		
				org.apache.cxf.endpoint.Client client = ClientProxy.getClient(port);
        Endpoint cxfEp = client.getEndpoint();

        Map<String, Object> outProps = new HashMap<String, Object>();
        outProps.put(WSHandlerConstants.ACTION,
                WSHandlerConstants.USERNAME_TOKEN+" "+WSHandlerConstants.TIMESTAMP);
        outProps.put(WSHandlerConstants.USER, "Test");
        outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        // 指定在调用远程ws之前触发的回调函数WsClinetAuthHandler,其实类似于一个拦截器
        outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
                wsss.ExampleServiceClientInterceptor.class.getName());
        cxfEp.getOutInterceptors().add(new WSS4JOutInterceptor(outProps));

        {
        System.out.println("Invoking sayHello...");
        String _sayHello_userName = "测试方法";
        String _sayHello__return = port.sayHello(_sayHello_userName);
        System.out.println("sayHello.result=" + _sayHello__return);


        }

        System.exit(0);
    }

}

 

 

 类似资料: