在上一篇CXF学习一中介绍了如何创建Server及Client,创建好Webservice之后部署到服务器就可以供其它的应用去访问,但在网络上不安全,任何的应用都可以去访问。为了保证Webservice的安全性,需要对Webservice提供认证,认证通过之后才可以访问服务,创建安全认证的步骤如下:
一、在Server端创建用户验证回调函数,回调函数如下:
public class ServerPasswordCallback implements CallbackHandler {
private Map<String,String> passwords=new HashMap<String,String>();
//在构造函数中初始化用户名和密码
public ServerPasswordCallback(){
passwords.put("test", "1234");
passwords.put("admin", "123");
passwords.put("test1", "storepassword");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for(int i=0;i<callbacks.length;i++){
WSPasswordCallback pc=(WSPasswordCallback)callbacks[i];
if(!passwords.containsKey(pc.getIdentifier()))
throw new WSSecurityException(" user name not match");
String password=passwords.get(pc.getIdentifier());
String pwd=pc.getPassword();
if(pwd==null||!pwd.equals(password)){
throw new WSSecurityException("password not match");
}
}
}
}
二、在Server端的applicationContext-cxf.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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- Load CXF modules from cxf.jar -->
<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" />
<jaxws:endpoint id="order"
implementor="cn.com.demo.order.service.impl.OrderServiceImpl"
address="/cxfOrder">
<!-- 拦截器 -->
<jaxws:inInterceptors>
<ref bean="wss4Jinterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
<!-- 服务端用户认证回调函数-->
<bean id="serverPasswordCallback" class="cn.com.demo.order.service.security.ServerPasswordCallback" />
<!--配置服务端拦截器-->
<bean id="wss4Jinterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" >
<constructor-arg>
<map>
<!--指定用户令牌-->
<entry key="action" value="UsernameToken"/>
<!-- 指定密码为文本格式 也可指定为 PasswordDigest -->
<entry key="passwordType" value="PasswordText"/>
<!-- 指定密码认证回调函数-->
<entry key="passwordCallbackRef">
<ref bean="serverPasswordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
</beans>
二、在Client创建密码认证回调函数
public class ClientPasswordCallback implements CallbackHandler {
private Map<String,String> passwords=new HashMap<String, String>();
public ClientPasswordCallback(){
passwords.put("test", "1234");
passwords.put("admin", "123");
passwords.put("test1", "storepassword");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for(int i=0;i<callbacks.length;i++){
WSPasswordCallback pc=(WSPasswordCallback)callbacks[i];
int usage=pc.getUsage();
if(!passwords.containsKey(pc.getIdentifier())){
throw new WSSecurityException("user not exists");
}
String pass=passwords.get(pc.getIdentifier());
if(usage==WSPasswordCallback.USERNAME_TOKEN&&pass!=null){
pc.setPassword(pass);
return;
}
}
}
}
三、在Client中的applicationContext_cxf_client.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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<!-- client service interface -->
<bean id="client" class="cn.com.cxf.demo.order.service.OrderProcess" factory-bean="clientFactory" factory-method="create" />
<!-- apache cxf jaxwsProxyFactorybean -->
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" >
<!-- service class -->
<property name="serviceClass" value="cn.com.cxf.demo.order.service.OrderProcess" />
<!-- service address -->
<property name="address" value="http://localhost:8080/orderdemo/services/cxfOrder" />
<!--登入拦截器--->
<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>
<!-- loggingIninterceptor -->
<bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<!-- loggingOutIntercepor -->
<bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
<!-- saaJoutInteceptor -->
<bean id="saajOut" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<!-- wss4JOutInterceptor -->
<bean id="wss4jOut" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<!--指定用户令牌-->
<entry key="action" value="UsernameToken" />
<!--指定密码为文本格式-->
<entry key="passwordType" value="PasswordText" />
<!--指定用户名为test-->
<entry key="user" value="test" />
<!--指定密码认证回调函数-->
<entry key="passwordCallbackClass"
value="cn.com.cxf.demo.order.service.security.ClientPasswordCallback" />
</map>
</constructor-arg>
</bean>
</beans>
四、创建Client、测试是否认证通过
public class CxfOrderClient {
public static void main(String args[]) throws Exception {
//读取客户端 Spring 配置文件
ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext(new String[] {"spring/applicationContext_cxf_client.xml"});
//获取客户端的Service接口
OrderProcess clientService=(OrderProcess) context.getBean("client");
clientService.getOrder("11");
System.out.println("===============updateOrder:"+clientService.updateOrder("11"));
System.out.println("===============getOrder:"+clientService.getOrder("11").getOrderId());
List<Order> list=clientService.queryOrder(new Date(), new Date());
for(int i=0;i<list.size();i++){
Order order=list.get(i);
System.out.println("================queryOrder:"+order.getOrderId());
}
}
}