CXF的webService已经创建好,但没有安全可言,毕竟这是Internet服务呀。
CXF给了一个很完整的安全架构,但CXF给出的ws_security DEMO太复杂了,又是password jks X509 Timestamp。 我试了很多次都没有成功。化繁为简,只实现一个user password好了。其实CXF和Spring——ACEGI的认证机制很像的都是使用了intercetor。
下面开始
编写cxf.xml在原来的bean的地方声明一下就可以了
- <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.mms.webservice.test.ServerPasswordCallback" />
- <!--
- 这里和上面的passwordCallbackClass效果一样,只不过是引用一个受管Bean,注入资源
- <entry key="passwordCallbackRef">
<ref bean="serverPasswordCallback"/>
</entry>
- 在外面的位置可以继续添加
- <bean id="serverPasswordCallback" adclass="cn.sz_sunshine.envinspector.security.ServerPasswordCallback">
<property name="userManager">
<ref bean="UserManager" />
</property>
</bean>
- -->
- </map>
- </constructor-arg>
- </bean>
-
- <jaxws:endpoint id="helloWorld"
- implementor="com.mms.webservice.HelloWorldImpl"
- address="/HelloWorld">
- <jaxws:inInterceptors>
- <!--
- <bean
- class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
- <bean
- 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.mms.webservice.test.ServerPasswordCallback" />
- </map>
- </constructor-arg>
- </bean>
- -->
- <ref bean="WSS4JInInterceptor" />
- </jaxws:inInterceptors>
- </jaxws:endpoint>
<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.mms.webservice.test.ServerPasswordCallback" />
</map>
</constructor-arg>
</bean>
<jaxws:endpoint id="helloWorld"
implementor="com.mms.webservice.HelloWorldImpl"
address="/HelloWorld">
<jaxws:inInterceptors>
<!--
<bean
class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<bean
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.mms.webservice.test.ServerPasswordCallback" />
</map>
</constructor-arg>
</bean>
-->
<ref bean="WSS4JInInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
WSS4JInInterceptor就是我们要定义的东东了。CXf已经帮你写好了。设置属性就可以了。里面属性值挺多的,CXF的文档就是太简单了,opensource的弊病!属性值就查API吧。
下面需要写server端的密码回调函数,验证logic就在这里定义了。
- package com.mms.webservice.test;
-
- import java.io.IOException;
- import java.util.ResourceBundle;
-
- 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 {
-
- private static final String BUNDLE_LOCATION = "com.mms.webservice.test.pass";
- private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";
-
- private static String password;
- static {
- final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
- password = bundle.getString(PASSWORD_PROPERTY_NAME);
- }
-
- public void handle(Callback[] callbacks) throws IOException,
- UnsupportedCallbackException {
-
- WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
-
-
-
-
-
- if (pc.getIdentifer().equalsIgnoreCase("eric")) {
- if (!pc.getPassword().equals(password)) {
- throw new SecurityException("wrong password");
- }
- }
- else
- {
- throw new SecurityException("the user does not exits");
- }
-
- }
-
- }
package com.mms.webservice.test;
import java.io.IOException;
import java.util.ResourceBundle;
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 {
private static final String BUNDLE_LOCATION = "com.mms.webservice.test.pass";
private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";
private static String password;
static {
final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
password = bundle.getString(PASSWORD_PROPERTY_NAME);
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
// Set the password on the callback. This will be compared to the
// password which was sent from the client.
// We can call pc.getIdentifer() right here to check the username
// if we want each client to have it's own password.
if (pc.getIdentifer().equalsIgnoreCase("eric")) {
if (!pc.getPassword().equals(password)) {
throw new SecurityException("wrong password");
}
}
else
{
throw new SecurityException("the user does not exits");
}
}
}
就此server端的验证就全部ok了。这时再调用原来的调用程序就会报ws_security错误了。
下面给出Client验证程序
其实就是在soapheader上加相应内容。也需要用到inInterceptors
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- package com.tnt.mms.webservice.client;
-
- import java.util.List;
-
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- import com.tnt.mms.webservice.VendorMaintenance;
- import com.tnt.mrm.model.other.Vendor;
-
- public final class ClientVendor {
-
- private ClientVendor() {
- }
-
- public static void main(String args[]) throws Exception {
-
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- new String[] { "com/tnt/mms/webservice/client/client-vendor-beans.xml" });
-
- try {
-
- VendorMaintenance client = (VendorMaintenance) context
- .getBean("client");
-
- Vendor ls = client.get("10116");
- System.out.println("Response: " + ls.getEngName());
-
- List<Vendor> rs = client.getList();
- System.out.println("Response: " + rs.size());
- System.out.println("Response: " + rs.get(0).getEngName());
-
- System.exit(0);
-
- } catch (Exception e) {
-
- e.printStackTrace();
- System.out.println("error" + e.getMessage());
-
- }
- }
- }
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.tnt.mms.webservice.client;
import java.util.List;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tnt.mms.webservice.VendorMaintenance;
import com.tnt.mrm.model.other.Vendor;
public final class ClientVendor {
private ClientVendor() {
}
public static void main(String args[]) throws Exception {
// START SNIPPET: client
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "com/tnt/mms/webservice/client/client-vendor-beans.xml" });
try {
VendorMaintenance client = (VendorMaintenance) context
.getBean("client");
Vendor ls = client.get("10116");
System.out.println("Response: " + ls.getEngName());
List<Vendor> rs = client.getList();
System.out.println("Response: " + rs.size());
System.out.println("Response: " + rs.get(0).getEngName());
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
System.out.println("error" + e.getMessage());
}
}
}
client_vendor_beans.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http:
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- -->
- <!-- START SNIPPET: beans -->
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:jaxws="http://cxf.apache.org/jaxws"
- xsi:schemaLocation="
- http:
- http:
- <!-- Configure CXF to use Aegis data binding instead of JAXB -->
- <bean id="aegisBean"
- class="org.apache.cxf.aegis.databinding.AegisDatabinding"
- scope="prototype" />
- <bean id="jaxwsAndAegisServiceFactory"
- class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"
- scope="prototype">
- <property name="dataBinding" ref="aegisBean" />
- <property name="serviceConfigurations">
- <list>
- <bean
- class="org.apache.cxf.jaxws.support.JaxWsServiceConfiguration" />
- <bean
- class="org.apache.cxf.aegis.databinding.AegisServiceConfiguration" />
- <bean
- class="org.apache.cxf.service.factory.DefaultServiceConfiguration" />
- </list>
- </property>
- </bean>
-
- <bean id="client" class="com.mms.webservice.VendorMaintenance"
- factory-bean="clientFactory" factory-method="create" />
-
- <bean id="clientFactory"
- class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
- <property name="serviceClass"
- value="com.mms.webservice.VendorMaintenance" />
- <property name="address"
- value="http://localhost:8080/extjsmms/services/VendorMaintenance" />
- <!-- <property name="serviceFactory" ref="jaxwsAndAegisServiceFactory"/> -->
- <property name="inInterceptors">
- <list>
- <ref bean="logIn" />
- </list>
- </property>
- <property name="outInterceptors">
- <list>
- <ref bean="logOut" />
- <ref bean="saajOut" />
- <ref bean="wss4jOut" />
- </list>
- </property>
- </bean>
-
-
- <bean id="logIn"
- class="org.apache.cxf.interceptor.LoggingInInterceptor" />
- <bean id="logOut"
- class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
- <bean id="saajOut"
- class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
- <bean id="wss4jOut"
- class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
- <constructor-arg>
- <map>
- <entry key="action" value="UsernameToken" />
- <entry key="user" value="eric" />
- <entry key="passwordType" value="PasswordText" />
- <entry key="passwordCallbackClass"
- value="com.mms.webservice.client.ClientPasswordCallback" />
- </map>
- </constructor-arg>
- </bean>
- </beans>
- <!-- END SNIPPET: beans -->
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!-- START SNIPPET: beans -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
<!-- Configure CXF to use Aegis data binding instead of JAXB -->
<bean id="aegisBean"
class="org.apache.cxf.aegis.databinding.AegisDatabinding"
scope="prototype" />
<bean id="jaxwsAndAegisServiceFactory"
class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"
scope="prototype">
<property name="dataBinding" ref="aegisBean" />
<property name="serviceConfigurations">
<list>
<bean
class="org.apache.cxf.jaxws.support.JaxWsServiceConfiguration" />
<bean
class="org.apache.cxf.aegis.databinding.AegisServiceConfiguration" />
<bean
class="org.apache.cxf.service.factory.DefaultServiceConfiguration" />
</list>
</property>
</bean>
<bean id="client" class="com.mms.webservice.VendorMaintenance"
factory-bean="clientFactory" factory-method="create" />
<bean id="clientFactory"
class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass"
value="com.mms.webservice.VendorMaintenance" />
<property name="address"
value="http://localhost:8080/extjsmms/services/VendorMaintenance" />
<!-- <property name="serviceFactory" ref="jaxwsAndAegisServiceFactory"/> -->
<property name="inInterceptors">
<list>
<ref bean="logIn" />
</list>
</property>
<property name="outInterceptors">
<list>
<ref bean="logOut" />
<ref bean="saajOut" />
<ref bean="wss4jOut" />
</list>
</property>
</bean>
<bean id="logIn"
class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="logOut"
class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<bean id="saajOut"
class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean id="wss4jOut"
class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="user" value="eric" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackClass"
value="com.mms.webservice.client.ClientPasswordCallback" />
</map>
</constructor-arg>
</bean>
</beans>
<!-- END SNIPPET: beans -->
至此验证成功。
在我的资源中有一个关于这方面的demo,有需要的朋友可以去下来学习一下