网上看的CXF+ws-secutiry大多是通过配置相关的xml文件来进行服务端部署,这儿给出不一样的做法。
web service接口及实现
package com.cxf.libraryServer; import javax.jws.WebMethod; @javax.jws.WebService public interface WebService { @WebMethod String serviceTest(); } package com.cxf.libraryServer; @javax.jws.WebService( name = "WebService", targetNamespace = "" ) public class WebServiceImpl implements WebService { @Override public String serviceTest() { return "success"; } }
服务端
1 package com.cxf.libraryServer.Server; 2 3 import com.cxf.libraryServer.WebService; 4 import com.cxf.libraryServer.WebServiceImpl; 5 import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor; 6 import org.apache.cxf.interceptor.LoggingInInterceptor; 7 import org.apache.cxf.interceptor.LoggingOutInterceptor; 8 import org.apache.cxf.jaxws.JaxWsServerFactoryBean; 9 import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor; 10 11 import java.util.HashMap; 12 import java.util.Map; 13 14 public class WebServicePublish { 15 public static void main(String[] args) { 16 String address = "wsdl地址"; 17 //采用JDK方式进行发布 18 // Endpoint.publish(address, new WebServiceImpl()); 1920 21 //采用JaxWsServerFactoryBean方式 22 JaxWsServerFactoryBean jaxWsServerFactoryBean = new JaxWsServerFactoryBean(); 23 //服务发布地址 24 jaxWsServerFactoryBean.setAddress(address); 25 //提供服务类的类型 26 jaxWsServerFactoryBean.setServiceClass(WebService.class); 27 //提供服务的实例 28 jaxWsServerFactoryBean.setServiceBean(new WebServiceImpl()); 29 // 30 Map<String, Object> props = new HashMap<String, Object>(); 31 props.put("action", "UsernameToken"); 32 props.put("passwordType", "PasswordDigest"); 33 props.put("user", "cxfname"); 34 props.put("passwordCallbackClass", "com.cxf.libraryServer.Server.ServerPasswordCallback"); 35 WSS4JInInterceptor wss4jIn = new org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor(props); 36 // 37 jaxWsServerFactoryBean.getInInterceptors().add(wss4jIn); 38 jaxWsServerFactoryBean.getInInterceptors().add((new SAAJInInterceptor())); 39 jaxWsServerFactoryBean.getInInterceptors().add(new LoggingInInterceptor()); 40 jaxWsServerFactoryBean.getInInterceptors().add(new LoggingOutInterceptor()); 41 //发布服务 42 jaxWsServerFactoryBean.create(); 43 System.out.println("图书馆接口发布成功"); 44 } 45 }
服务端回调函数:用于验证密码
package com.libraryServer.Server; import org.apache.wss4j.common.ext.WSPasswordCallback; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import java.io.IOException; public class ServerPasswordCallback implements CallbackHandler { public void handle(Callback[] args) throws IOException,UnsupportedCallbackException { for (int i = 0; i < args.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) args[i]; String identifier = pc.getIdentifier(); if ("cxfname".equals(identifier)) { pc.setPassword("admin"); } } } }
客户端
package com.cxf.libraryServer.ClientTest; import com.cxf.libraryServer.WebService; import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor; import java.util.HashMap; import java.util.Map; public class Client { public WebService UserAccess() { try { String REMOTEDATA_CXF_NAME = "cxfname"; String REMOTEDATA_CXF_WSDL = "wsdl地址"; JaxWsProxyFactoryBean jwpFactory = new JaxWsProxyFactoryBean(); jwpFactory.setAddress(REMOTEDATA_CXF_WSDL); jwpFactory.setServiceClass(WebService.class); // Map<String, Object> outProps = new HashMap<String, Object>(); outProps.put("action", "UsernameToken"); outProps.put("user", REMOTEDATA_CXF_NAME); outProps.put("passwordType", "PasswordDigest"); outProps.put("passwordCallbackClass", "com.cxf.libraryServer.ClientTest.WSAuthHandler"); WSS4JOutInterceptor wss4jOut = new org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor(outProps); // jwpFactory.getOutInterceptors().add(wss4jOut); jwpFactory.getOutInterceptors().add(new SAAJOutInterceptor()); jwpFactory.getOutInterceptors().add(new LoggingOutInterceptor()); jwpFactory.getOutInterceptors().add(new LoggingInInterceptor()); return (WebService) jwpFactory.create(); } catch (Exception e) { e.printStackTrace(); } return null; } }
客户端回调函数:用于发送密码
package com.cxf.libraryServer.ClientTest; import org.apache.wss4j.common.ext.WSPasswordCallback; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import java.io.IOException; public class WSAuthHandler implements CallbackHandler { @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; // 这里必须设置密码,否则会抛出:java.lang.IllegalArgumentException: pwd == null // but a password is needed pc.setPassword("admin"); } } }
测试结果:在test层中测试
@Test public void myCXF_WebserviceTest(){ Client client = new Client(); WebService webService = client.UserAccess(); System.out.println(webService.serviceTest()); }
成功打印出:success
参考资料
Java code examples for org.apache.cxf.ws.ssecurity.wss4j.Wss4JOutInterceptor
浅谈springmvc整合CXF+ws-security实现wbservice安全验证
(ps:服务端发布是直接写main来测试,在项目中可以直接写个servlet来进行启动cxf服务,详细操作可以见:Java web项目启动时,自动执行代码的三种方式)