公司最近要采用CXF Web Service技术,本人写了个Demo,一路还都OK,但是就是在加入安全认证时出现问题,在百度、谷歌搜索了N久,参考修改了N久,还是解决不了,自己本人都解决吐了,现在求各位大神,大牛解决。
问题:(1)没有加入认证时,客户端连接请求成功!
(2)加入安全认证后,出现bug,在eclipse和MyEclipse出现的报错信息还不一样。
一、服务器代码:
1、ServerPasswordCallbackHandler.java 安全拦截器
package com.credit56.demo.cxf.handler.soap; 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.wss4j.common.ext.WSPasswordCallback; /** * <p class="detail"> * 功能:服务端的密码回调处理类 * </p> * * @ClassName: ClassServerPasswordCallbackHandler * @version V1.0 * @date 2013年12月24日 * @author <a href="">qinhailong</a> */ public class ServerPasswordCallbackHandler implements CallbackHandler { public static final String USER = "shuqin_wang"; public static final String PASSWORD = "000000"; /** * <p class="detail"> * 功能: * </p> * * @author <a href="mailto:engineer01@great-tao.com">qinhailong</a> * @date 2013年12月24日 * @param callbacks * @throws IOException * @throws UnsupportedCallbackException * @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[]) */ @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback wsPasswordCallBack = (WSPasswordCallback) callbacks[0]; System.out.println(wsPasswordCallBack.getIdentifier() + "\t" + wsPasswordCallBack.getPassword()); if (USER.equals(wsPasswordCallBack.getIdentifier()) && PASSWORD.equals(wsPasswordCallBack.getPassword())) { System.out.println("======= Successful ! ======="); } else { // throw new WSSecurityException("No Permission!"); } } }
2.IGreetingService 接口
package com.credit56.demo.cxf.service; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; import com.credit56.demo.cxf.model.Customer; /** * * <p class="detail"> * 功能:Hello World web service Demo * </p> * * @ClassName: HelloWordService * @version V1.0 * @date 2013年12月18日 * @author <a href="">qinhailong</a> */ @WebService public interface IGreetingService { @WebMethod // public String sayHello(@WebParam(name="name") String name); // 通过@WebParam(name="***")来设置WSDL中的参数名称,默认为arg0、arg1...... public String greeting(@WebParam(name = "name") String name); @WebMethod public Customer getCustomer(@WebParam(name = "customer") Customer customer); @WebMethod public String getCustomerOfJSON(); }
3.GreetingServiceImpl.java 实现类
package com.credit56.demo.cxf.service.impl; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Set; import javax.annotation.Resource; import javax.xml.ws.WebServiceContext; import javax.xml.ws.handler.MessageContext; import net.sf.json.JSONObject; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; import org.apache.cxf.jaxws.JaxWsServerFactoryBean; import com.credit56.demo.cxf.model.Customer; import com.credit56.demo.cxf.service.IGreetingService; /** * <p class="detail"> * 功能:web service Demo * </p> * * @ClassName: HelloWorldServiceImpl * @version V1.0 * @date 2013年12月18日 * @author <a href="">qinhailong</a> */ public class GreetingServiceImpl implements IGreetingService { @Resource private WebServiceContext webServiceContext; /** * <p class="detail"> * 功能:问候语 * </p> * * @author <a href="">qinhailong</a> * @date 2013年12月18日 * @param name * @return * @see com.credit56.demo.cxf.handler.soap.service.IGreetingService#sayHello(java.lang.String) */ @Override public String greeting(String name) { System.out.println("进来了,亲,好啊=====" + name); return new StringBuffer(name).append(",Hello Word! currentTime is ").append(new Date()).toString(); } /** * * <p class="detail"> * 功能:返回Customer * </p> * * @author <a href="">qinhailong</a> * @date 2013年12月19日 * @param customer * @return * @see com.credit56.demo.cxf.handler.soap.service.IGreetingService#getCustomer(com.credit56.demo.cxf.handler.soap.model.Customer) */ @Override public Customer getCustomer(Customer customer) { MessageContext messageContext = webServiceContext.getMessageContext(); Set<String> keySets = messageContext.keySet(); for (String key : keySets) { System.out.println("=======key:" + messageContext.get(key)); /* * try { System.out.println("+++++++++scope:" + * messageContext.getScope(key)); } catch (Exception e) { * System.out.println("+++++++++++"+ key + "is not exits"); } */ } if (null != customer.getId()) { return customer; } Customer c = new Customer(); c.setId(1L); c.setBirthday(new SimpleDateFormat("yyyy-MM-dd").format(new Date())); c.setName("shuqin_wang"); return c; } /** * * <p class="detail"> * 功能:返回客户信息JOSN * </p> * * @author <a href="">qinhailong</a> * @date 2013年12月19日 * @return * @see com.credit56.demo.cxf.handler.soap.service.IGreetingService#getCustomerOfJSON() */ @Override public String getCustomerOfJSON() { Customer customer = this.getCustomer(new Customer()); JSONObject jsonObject = JSONObject.fromObject(customer); return jsonObject.toString(); } }
4.服务端applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <!-- Import Apache CXF Bean Definition --> <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" /> <bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="passwordType" value="PasswordText" /> <entry key="passwordCallbackClass" value="com.credit56.demo.cxf.handler.soap.ServerPasswordCallbackHandler" /> </map> </constructor-arg> </bean> <jaxws:endpoint id="greetingService" implementor="com.credit56.demo.cxf.service.impl.GreetingServiceImpl" address="/greetingService"> <jaxws:inInterceptors> <ref bean="wss4jInInterceptor" /> </jaxws:inInterceptors> </jaxws:endpoint> <bean id="studentService" class="com.credit56.demo.cxf.service.impl.StudentServiceImpl" /> <jaxrs:server id="studentServiceWs" address="/studentService"> <jaxrs:serviceBeans> <ref bean="studentService" /> </jaxrs:serviceBeans> </jaxrs:server> </beans>
二、客户端:
1、客户端认证拦截器(out)
package com.credit56.demo.cxf.client.soap.handler; 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.wss4j.common.ext.WSPasswordCallback; /** * <p class="detail"> * 功能:这里写描述 * </p> * * @ClassName: ClientPasswordCallbackHandler * @version V1.0 * @date 2013年12月24日 * @author <a href="">qinhailong</a> */ public class ClientPasswordCallbackHandler implements CallbackHandler { public final static String USER = "shuqin_wang"; public final static String PASSWORD = "000000"; /** * <p class="detail"> * 功能: * </p> * * @author <a href=""></a> * @date 2013年12月24日 * @param callbacks * @throws IOException * @throws UnsupportedCallbackException * @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[]) */ @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0]; wsPasswordCallback.setPassword(PASSWORD); wsPasswordCallback.setIdentifier(USER); System.out.println("~~~~~~~out OK!~~~~~~"); } }
2、main客户端调用
package com.credit56.demo.cxf.client; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.credit56.demo.cxf.client.model.Customer; import com.credit56.demo.cxf.client.service.IGreetingService; //org/apache/xml/security/resource/xmlsecurity import org.apache.xml.security.resource.schema.*; public class CXFTest { public static void main(String[] args) { System.out.println("======"+ System.getProperty("java.endorsed.dirs")); IGreetingService greetingServiceClient = (IGreetingService) new ClassPathXmlApplicationContext( "classpath:applicationContext.xml").getBean("greetingServiceClient"); //greetingServiceClient.greeting("shuqin_wang"); Customer customer = new Customer(); customer.setId(1L); customer.setBirthday(new SimpleDateFormat("yyyy-MM-dd").format(new Date())); customer.setName("hailong_qin"); Customer c = greetingServiceClient.getCustomer(customer); System.out.println("id:" + c.getId() + " name:" + c.getName() + " birthday:" + c.getBirthday()); System.out.println(greetingServiceClient.getCustomerOfJSON()); } }
3、客户端 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <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-extension-jaxrs-binding.xml" /> --> <import resource="classpath*:META-INF/cxf/cxf-servlet.xml" /> <bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"> <constructor-arg> <map> <entry key="action" value="UsernameToken" /> <entry key="user" value="shuqin_wang" /> <entry key="passwordType" value="PasswordText" /> <entry key="passwordCallbackClass" value="com.credit56.demo.cxf.client.soap.handler.ClientPasswordCallbackHandler" /> </map> </constructor-arg> </bean> <!-- 通过与服务端配置相对的 CXF 标签 <jaxws:client> 来定义客户端访问服务的声明 --> <jaxws:client id="greetingServiceClient" serviceClass="com.credit56.demo.cxf.client.service.IGreetingService" address="http://localhost:80/cxfdemo/greetingService"> <jaxws:outInterceptors> <ref bean="wss4jOutInterceptor" /> </jaxws:outInterceptors> </jaxws:client> </beans>
三、不同的开发环境报错信息居然不一样:
1、MyEclipse环境报错信息:
24 17:33:40 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromClass 信息: Creating Service {http://service.client.cxf.demo.credit56.com/}IGreetingServiceService from class com.credit56.demo.cxf.client.service.IGreetingService Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceClient': FactoryBean threw exception on object creation; nested exception is java.lang.LinkageError: 正在从引导类加载器加载 JAXB 2.1 API, 但此 RI (来自jar:file:/F:/cxflib/apache-cxf-3.0.0-milestone1/lib/jaxb-impl-2.2.6.jar!/com/sun/xml/bind/v2/model/impl/ModelBuilder.class) 需要 2.2 API。请使用授权目录机制将 jaxb-api.jar 放在引导类加载器中。(请参阅 http://java.sun.com/j2se/1.6.0/docs/guide/standards/) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:149) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:102) at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1468) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:249) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117) at com.credit56.demo.cxf.client.CXFTest.main(CXFTest.java:16) Caused by: java.lang.LinkageError: 正在从引导类加载器加载 JAXB 2.1 API, 但此 RI (来自jar:file:/F:/cxflib/apache-cxf-3.0.0-milestone1/lib/jaxb-impl-2.2.6.jar!/com/sun/xml/bind/v2/model/impl/ModelBuilder.class) 需要 2.2 API。请使用授权目录机制将 jaxb-api.jar 放在引导类加载器中。(请参阅 http://java.sun.com/j2se/1.6.0/docs/guide/standards/) at com.sun.xml.bind.v2.model.impl.ModelBuilder.<clinit>(ModelBuilder.java:178) at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:455) at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:303) at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:142) at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1174) at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:162) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:210) at javax.xml.bind.ContextFinder.find(ContextFinder.java:368) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574) at org.apache.cxf.common.jaxb.JAXBContextCache$2.run(JAXBContextCache.java:331) at org.apache.cxf.common.jaxb.JAXBContextCache$2.run(JAXBContextCache.java:329) at java.security.AccessController.doPrivileged(Native Method) at org.apache.cxf.common.jaxb.JAXBContextCache.createContext(JAXBContextCache.java:329) at org.apache.cxf.common.jaxb.JAXBContextCache.getCachedContextAndSchemas(JAXBContextCache.java:230) at org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:465) at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:322) at org.apache.cxf.service.factory.AbstractServiceFactoryBean.initializeDataBindings(AbstractServiceFactoryBean.java:86) at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.buildServiceFromClass(ReflectionServiceFactoryBean.java:490) at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.buildServiceFromClass(JaxWsServiceFactoryBean.java:704) at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:550) at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:265) at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:215) at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:102) at org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:91) at org.apache.cxf.frontend.ClientProxyFactoryBean.create(ClientProxyFactoryBean.java:157) at org.apache.cxf.jaxws.JaxWsProxyFactoryBean.create(JaxWsProxyFactoryBean.java:142) at org.apache.cxf.jaxws.spring.JaxWsProxyFactoryBeanDefinitionParser$JAXWSSpringClientProxyFactoryBean.create(JaxWsProxyFactoryBeanDefinitionParser.java:79) at org.apache.cxf.jaxws.spring.JaxWsProxyFactoryBeanDefinitionParser$JAXWSSpringClientProxyFactoryBean.getObject(JaxWsProxyFactoryBeanDefinitionParser.java:83) at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142) ... 6 more
2、Eclipse环境报错:
警告: Interceptor for {http://service.client.cxf.demo.credit56.com/}IGreetingServiceService#{http://service.client.cxf.demo.credit56.com/}getCustomer has thrown exception, unwinding now java.util.MissingResourceException: Can't find bundle for base name org/apache/xml/security/resource/xmlsecurity, locale zh_CN at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1499) at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1322) at java.util.ResourceBundle.getBundle(ResourceBundle.java:721) at org.apache.wss4j.common.crypto.WSProviderConfig$4.<init>(WSProviderConfig.java:138) at org.apache.wss4j.common.crypto.WSProviderConfig.initializeResourceBundles(WSProviderConfig.java:135) at org.apache.wss4j.common.crypto.WSProviderConfig.init(WSProviderConfig.java:69) at org.apache.wss4j.dom.WSSConfig.init(WSSConfig.java:387) at org.apache.wss4j.dom.WSSConfig.getNewInstance(WSSConfig.java:394) at org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal.handleMessage(WSS4JOutInterceptor.java:180) at org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal.handleMessage(WSS4JOutInterceptor.java:140) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:502) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:411) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:267) at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96) at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:137) at com.sun.proxy.$Proxy39.getCustomer(Unknown Source) at com.credit56.demo.cxf.client.CXFTest.main(CXFTest.java:28) Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Can't find bundle for base name org/apache/xml/security/resource/xmlsecurity, locale zh_CN at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:159) at com.sun.proxy.$Proxy39.getCustomer(Unknown Source) at com.credit56.demo.cxf.client.CXFTest.main(CXFTest.java:28) Caused by: java.util.MissingResourceException: Can't find bundle for base name org/apache/xml/security/resource/xmlsecurity, locale zh_CN at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:1499) at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1322) at java.util.ResourceBundle.getBundle(ResourceBundle.java:721) at org.apache.wss4j.common.crypto.WSProviderConfig$4.<init>(WSProviderConfig.java:138) at org.apache.wss4j.common.crypto.WSProviderConfig.initializeResourceBundles(WSProviderConfig.java:135) at org.apache.wss4j.common.crypto.WSProviderConfig.init(WSProviderConfig.java:69) at org.apache.wss4j.dom.WSSConfig.init(WSSConfig.java:387) at org.apache.wss4j.dom.WSSConfig.getNewInstance(WSSConfig.java:394) at org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal.handleMessage(WSS4JOutInterceptor.java:180) at org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor$WSS4JOutInterceptorInternal.handleMessage(WSS4JOutInterceptor.java:140) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:502) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:411) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314) at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:267) at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96) at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:137) ... 2 more
四、尝试过的方法:
1、找到相应位置,将apache-cxf-2.7.4\lib\endorsed下的jar文件放到对应目录下即可。如果没有endorsed目录,则手动建立该目录。
2、JDK升级到1.7
3、等等
五、附上源代码
1、cxfdemo.zip ---服务端代码
2、csfdemoclient.zip --- 客户端代码
1 楼
iuhoay
昨天
main 方法里 Spring 路径错了